dataTables.searchBuilder.js 157 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559
  1. /*! SearchBuilder 1.1.0
  2. * ©SpryMedia Ltd - datatables.net/license/mit
  3. */
  4. (function () {
  5. 'use strict';
  6. var $$2;
  7. var dataTable$2;
  8. // eslint-disable-next-line no-extra-parens
  9. var moment = window.moment;
  10. // eslint-disable-next-line no-extra-parens
  11. var luxon = window.luxon;
  12. /**
  13. * Sets the value of jQuery for use in the file
  14. *
  15. * @param jq the instance of jQuery to be set
  16. */
  17. function setJQuery$2(jq) {
  18. $$2 = jq;
  19. dataTable$2 = jq.fn.dataTable;
  20. }
  21. /**
  22. * The Criteria class is used within SearchBuilder to represent a search criteria
  23. */
  24. var Criteria = /** @class */ (function () {
  25. function Criteria(table, opts, topGroup, index, depth) {
  26. var _this = this;
  27. if (index === void 0) { index = 0; }
  28. if (depth === void 0) { depth = 1; }
  29. // Check that the required version of DataTables is included
  30. if (!dataTable$2 || !dataTable$2.versionCheck || !dataTable$2.versionCheck('1.10.0')) {
  31. throw new Error('SearchPane requires DataTables 1.10 or newer');
  32. }
  33. this.classes = $$2.extend(true, {}, Criteria.classes);
  34. // Get options from user and any extra conditions/column types defined by plug-ins
  35. this.c = $$2.extend(true, {}, Criteria.defaults, $$2.fn.dataTable.ext.searchBuilder, opts);
  36. var i18n = this.c.i18n;
  37. this.s = {
  38. condition: undefined,
  39. conditions: {},
  40. data: undefined,
  41. dataIdx: -1,
  42. dataPoints: [],
  43. dateFormat: false,
  44. depth: depth,
  45. dt: table,
  46. filled: false,
  47. index: index,
  48. origData: undefined,
  49. topGroup: topGroup,
  50. type: '',
  51. value: []
  52. };
  53. this.dom = {
  54. buttons: $$2('<div/>')
  55. .addClass(this.classes.buttonContainer),
  56. condition: $$2('<select disabled/>')
  57. .addClass(this.classes.condition)
  58. .addClass(this.classes.dropDown)
  59. .addClass(this.classes.italic)
  60. .attr('autocomplete', 'hacking'),
  61. conditionTitle: $$2('<option value="" disabled selected hidden/>')
  62. .text(this.s.dt.i18n('searchBuilder.condition', i18n.condition)),
  63. container: $$2('<div/>')
  64. .addClass(this.classes.container),
  65. data: $$2('<select/>')
  66. .addClass(this.classes.data)
  67. .addClass(this.classes.dropDown)
  68. .addClass(this.classes.italic),
  69. dataTitle: $$2('<option value="" disabled selected hidden/>')
  70. .text(this.s.dt.i18n('searchBuilder.data', i18n.data)),
  71. defaultValue: $$2('<select disabled/>')
  72. .addClass(this.classes.value)
  73. .addClass(this.classes.dropDown)
  74. .addClass(this.classes.select),
  75. "delete": $$2('<button>&times</button>')
  76. .addClass(this.classes["delete"])
  77. .addClass(this.classes.button)
  78. .attr('title', this.s.dt.i18n('searchBuilder.deleteTitle', i18n.deleteTitle))
  79. .attr('type', 'button'),
  80. // eslint-disable-next-line no-useless-escape
  81. left: $$2('<button>\<</button>')
  82. .addClass(this.classes.left)
  83. .addClass(this.classes.button)
  84. .attr('title', this.s.dt.i18n('searchBuilder.leftTitle', i18n.leftTitle))
  85. .attr('type', 'button'),
  86. // eslint-disable-next-line no-useless-escape
  87. right: $$2('<button>\></button>')
  88. .addClass(this.classes.right)
  89. .addClass(this.classes.button)
  90. .attr('title', this.s.dt.i18n('searchBuilder.rightTitle', i18n.rightTitle))
  91. .attr('type', 'button'),
  92. value: [
  93. $$2('<select disabled/>')
  94. .addClass(this.classes.value)
  95. .addClass(this.classes.dropDown)
  96. .addClass(this.classes.italic)
  97. .addClass(this.classes.select)
  98. ],
  99. valueTitle: $$2('<option value="--valueTitle--" selected/>')
  100. .text(this.s.dt.i18n('searchBuilder.value', i18n.value))
  101. };
  102. // If the greyscale option is selected then add the class to add the grey colour to SearchBuilder
  103. if (this.c.greyscale) {
  104. this.dom.data.addClass(this.classes.greyscale);
  105. this.dom.condition.addClass(this.classes.greyscale);
  106. this.dom.defaultValue.addClass(this.classes.greyscale);
  107. for (var _i = 0, _a = this.dom.value; _i < _a.length; _i++) {
  108. var val = _a[_i];
  109. val.addClass(this.classes.greyscale);
  110. }
  111. }
  112. // For responsive design, adjust the criterias properties on the following events
  113. this.s.dt.on('draw.dtsp', function () {
  114. _this._adjustCriteria();
  115. });
  116. this.s.dt.on('buttons-action', function () {
  117. _this._adjustCriteria();
  118. });
  119. $$2(window).on('resize.dtsp', dataTable$2.util.throttle(function () {
  120. _this._adjustCriteria();
  121. }));
  122. this._buildCriteria();
  123. return this;
  124. }
  125. /**
  126. * Adds the left button to the criteria
  127. */
  128. Criteria.prototype.updateArrows = function (hasSiblings, redraw) {
  129. if (hasSiblings === void 0) { hasSiblings = false; }
  130. if (redraw === void 0) { redraw = true; }
  131. // Empty the container and append all of the elements in the correct order
  132. this.dom.container.children().detach();
  133. this.dom.container
  134. .append(this.dom.data)
  135. .append(this.dom.condition)
  136. .append(this.dom.value[0]);
  137. this.setListeners();
  138. // Trigger the inserted events for the value elements as they are inserted
  139. if (this.dom.value[0] !== undefined) {
  140. this.dom.value[0].trigger('dtsb-inserted');
  141. }
  142. for (var i = 1; i < this.dom.value.length; i++) {
  143. this.dom.container.append(this.dom.value[i]);
  144. this.dom.value[i].trigger('dtsb-inserted');
  145. }
  146. // If this is a top level criteria then don't let it move left
  147. if (this.s.depth > 1) {
  148. this.dom.buttons.append(this.dom.left);
  149. }
  150. // If the depthLimit of the query has been hit then don't add the right button
  151. if ((this.c.depthLimit === false || this.s.depth < this.c.depthLimit) && hasSiblings) {
  152. this.dom.buttons.append(this.dom.right);
  153. }
  154. else {
  155. this.dom.right.remove();
  156. }
  157. this.dom.buttons.append(this.dom["delete"]);
  158. this.dom.container.append(this.dom.buttons);
  159. if (redraw) {
  160. // A different combination of arrows and selectors may lead to a need for responsive to be triggered
  161. this._adjustCriteria();
  162. }
  163. };
  164. /**
  165. * Destroys the criteria, removing listeners and container from the dom
  166. */
  167. Criteria.prototype.destroy = function () {
  168. // Turn off listeners
  169. this.dom.data.off('.dtsb');
  170. this.dom.condition.off('.dtsb');
  171. this.dom["delete"].off('.dtsb');
  172. for (var _i = 0, _a = this.dom.value; _i < _a.length; _i++) {
  173. var val = _a[_i];
  174. val.off('.dtsb');
  175. }
  176. // Remove container from the dom
  177. this.dom.container.remove();
  178. };
  179. /**
  180. * Passes in the data for the row and compares it against this single criteria
  181. *
  182. * @param rowData The data for the row to be compared
  183. * @returns boolean Whether the criteria has passed
  184. */
  185. Criteria.prototype.search = function (rowData, rowIdx) {
  186. var condition = this.s.conditions[this.s.condition];
  187. if (this.s.condition !== undefined && condition !== undefined) {
  188. var filter = rowData[this.s.dataIdx];
  189. // This check is in place for if a custom decimal character is in place
  190. if (this.s.type.includes('num') &&
  191. (this.s.dt.settings()[0].oLanguage.sDecimal !== '' ||
  192. this.s.dt.settings()[0].oLanguage.sThousands !== '')) {
  193. var splitRD = [rowData[this.s.dataIdx]];
  194. if (this.s.dt.settings()[0].oLanguage.sDecimal !== '') {
  195. splitRD = rowData[this.s.dataIdx].split(this.s.dt.settings()[0].oLanguage.sDecimal);
  196. }
  197. if (this.s.dt.settings()[0].oLanguage.sThousands !== '') {
  198. for (var i = 0; i < splitRD.length; i++) {
  199. splitRD[i] = splitRD[i].replace(this.s.dt.settings()[0].oLanguage.sThousands, ',');
  200. }
  201. }
  202. filter = splitRD.join('.');
  203. }
  204. // If orthogonal data is in place we need to get it's values for searching
  205. if (this.c.orthogonal.search !== 'filter') {
  206. var settings = this.s.dt.settings()[0];
  207. filter = settings.oApi._fnGetCellData(settings, rowIdx, this.s.dataIdx, typeof this.c.orthogonal === 'string' ?
  208. this.c.orthogonal :
  209. this.c.orthogonal.search);
  210. }
  211. if (this.s.type === 'array') {
  212. // Make sure we are working with an array
  213. if (!Array.isArray(filter)) {
  214. filter = [filter];
  215. }
  216. filter.sort();
  217. for (var _i = 0, filter_1 = filter; _i < filter_1.length; _i++) {
  218. var filt = filter_1[_i];
  219. if (filt) {
  220. filt = filt.replace(/[\r\n\u2028]/g, ' ');
  221. }
  222. }
  223. }
  224. else if (filter !== null) {
  225. filter = filter.replace(/[\r\n\u2028]/g, ' ');
  226. }
  227. if (this.s.type.includes('html')) {
  228. filter = filter.replace(/(<([^>]+)>)/ig, '');
  229. }
  230. // Not ideal, but jqueries .val() returns an empty string even
  231. // when the value set is null, so we shall assume the two are equal
  232. if (filter === null) {
  233. filter = '';
  234. }
  235. return condition.search(filter, this.s.value, this);
  236. }
  237. };
  238. /**
  239. * Gets the details required to rebuild the criteria
  240. */
  241. Criteria.prototype.getDetails = function () {
  242. var value = this.s.value;
  243. // This check is in place for if a custom decimal character is in place
  244. if (this.s.type !== null &&
  245. this.s.type.includes('num') &&
  246. (this.s.dt.settings()[0].oLanguage.sDecimal !== '' || this.s.dt.settings()[0].oLanguage.sThousands !== '')) {
  247. for (var i = 0; i < this.s.value.length; i++) {
  248. var splitRD = [this.s.value[i].toString()];
  249. if (this.s.dt.settings()[0].oLanguage.sDecimal !== '') {
  250. splitRD = this.s.value[i].split(this.s.dt.settings()[0].oLanguage.sDecimal);
  251. }
  252. if (this.s.dt.settings()[0].oLanguage.sThousands !== '') {
  253. for (var j = 0; j < splitRD.length; j++) {
  254. splitRD[j] = splitRD[j].replace(this.s.dt.settings()[0].oLanguage.sThousands, ',');
  255. }
  256. }
  257. this.s.value[i] = splitRD.join('.');
  258. }
  259. }
  260. return {
  261. condition: this.s.condition,
  262. data: this.s.data,
  263. origData: this.s.origData,
  264. value: value
  265. };
  266. };
  267. /**
  268. * Getter for the node for the container of the criteria
  269. *
  270. * @returns JQuery<HTMLElement> the node for the container
  271. */
  272. Criteria.prototype.getNode = function () {
  273. return this.dom.container;
  274. };
  275. /**
  276. * Populates the criteria data, condition and value(s) as far as has been selected
  277. */
  278. Criteria.prototype.populate = function () {
  279. this._populateData();
  280. // If the column index has been found attempt to select a condition
  281. if (this.s.dataIdx !== -1) {
  282. this._populateCondition();
  283. // If the condittion has been found attempt to select the values
  284. if (this.s.condition !== undefined) {
  285. this._populateValue();
  286. }
  287. }
  288. };
  289. /**
  290. * Rebuilds the criteria based upon the details passed in
  291. *
  292. * @param loadedCriteria the details required to rebuild the criteria
  293. */
  294. Criteria.prototype.rebuild = function (loadedCriteria) {
  295. // Check to see if the previously selected data exists, if so select it
  296. var foundData = false;
  297. var dataIdx;
  298. this._populateData();
  299. // If a data selection has previously been made attempt to find and select it
  300. if (loadedCriteria.data !== undefined) {
  301. var italic_1 = this.classes.italic;
  302. var data_1 = this.dom.data;
  303. this.dom.data.children('option').each(function () {
  304. if ($$2(this).text() === loadedCriteria.data) {
  305. $$2(this).attr('selected', true);
  306. data_1.removeClass(italic_1);
  307. foundData = true;
  308. dataIdx = $$2(this).val();
  309. }
  310. });
  311. }
  312. // If the data has been found and selected then the condition can be populated and searched
  313. if (foundData) {
  314. this.s.data = loadedCriteria.data;
  315. this.s.origData = loadedCriteria.origData;
  316. this.s.dataIdx = dataIdx;
  317. this.c.orthogonal = this._getOptions().orthogonal;
  318. this.dom.dataTitle.remove();
  319. this._populateCondition();
  320. this.dom.conditionTitle.remove();
  321. var condition_1;
  322. // Check to see if the previously selected condition exists, if so select it
  323. this.dom.condition.children('option').each(function () {
  324. if (loadedCriteria.condition !== undefined &&
  325. $$2(this).val() === loadedCriteria.condition &&
  326. typeof loadedCriteria.condition === 'string') {
  327. $$2(this).attr('selected', true);
  328. condition_1 = $$2(this).val();
  329. }
  330. });
  331. this.s.condition = condition_1;
  332. // If the condition has been found and selected then the value can be populated and searched
  333. if (this.s.condition !== undefined) {
  334. this.dom.conditionTitle.remove();
  335. this.dom.condition.removeClass(this.classes.italic);
  336. this._populateValue(loadedCriteria);
  337. }
  338. else {
  339. this.dom.conditionTitle.prependTo(this.dom.condition).attr('selected', 'true');
  340. }
  341. }
  342. };
  343. /**
  344. * Sets the listeners for the criteria
  345. */
  346. Criteria.prototype.setListeners = function () {
  347. var _this = this;
  348. this.dom.data
  349. .unbind('change')
  350. .on('change', function () {
  351. _this.dom.dataTitle.attr('selected', 'false');
  352. _this.dom.data.removeClass(_this.classes.italic);
  353. _this.s.dataIdx = +_this.dom.data.children('option:selected').val();
  354. _this.s.data = _this.dom.data.children('option:selected').text();
  355. _this.s.origData = _this.dom.data.children('option:selected').attr('origData');
  356. _this.c.orthogonal = _this._getOptions().orthogonal;
  357. // When the data is changed, the values in condition and value may also change so need to renew them
  358. _this._clearCondition();
  359. _this._clearValue();
  360. _this._populateCondition();
  361. // If this criteria was previously active in the search then
  362. // remove it from the search and trigger a new search
  363. if (_this.s.filled) {
  364. _this.s.filled = false;
  365. _this.s.dt.draw();
  366. _this.setListeners();
  367. }
  368. _this.s.dt.state.save();
  369. });
  370. this.dom.condition
  371. .unbind('change')
  372. .on('change', function () {
  373. _this.dom.conditionTitle.attr('selected', 'false');
  374. _this.dom.condition.removeClass(_this.classes.italic);
  375. var condDisp = _this.dom.condition.children('option:selected').val();
  376. // Find the condition that has been selected and store it internally
  377. for (var _i = 0, _a = Object.keys(_this.s.conditions); _i < _a.length; _i++) {
  378. var cond = _a[_i];
  379. if (cond === condDisp) {
  380. _this.s.condition = condDisp;
  381. break;
  382. }
  383. }
  384. // When the condition is changed, the value selector may switch between
  385. // a select element and an input element
  386. _this._clearValue();
  387. _this._populateValue();
  388. for (var _b = 0, _c = _this.dom.value; _b < _c.length; _b++) {
  389. var val = _c[_b];
  390. // If this criteria was previously active in the search then remove
  391. // it from the search and trigger a new search
  392. if (_this.s.filled && val !== undefined && _this.dom.container.has(val[0]).length !== 0) {
  393. _this.s.filled = false;
  394. _this.s.dt.draw();
  395. _this.setListeners();
  396. }
  397. }
  398. if (_this.dom.value.length === 0 || _this.dom.value.length === 1 && _this.dom.value[0] === undefined) {
  399. _this.s.dt.draw();
  400. }
  401. });
  402. };
  403. /**
  404. * Adjusts the criteria to make SearchBuilder responsive
  405. */
  406. Criteria.prototype._adjustCriteria = function () {
  407. // If this criteria is not present then don't bother adjusting it
  408. if ($$2(document).has(this.dom.container).length === 0) {
  409. return;
  410. }
  411. var valRight;
  412. var valWidth;
  413. var outmostval = this.dom.value[this.dom.value.length - 1];
  414. // Calculate the width and right value of the outmost value element
  415. if (outmostval !== undefined && this.dom.container.has(outmostval[0]).length !== 0) {
  416. valWidth = outmostval.outerWidth(true);
  417. valRight = outmostval.offset().left + valWidth;
  418. }
  419. else {
  420. return;
  421. }
  422. var leftOffset = this.dom.left.offset();
  423. var rightOffset = this.dom.right.offset();
  424. var clearOffset = this.dom["delete"].offset();
  425. var hasLeft = this.dom.container.has(this.dom.left[0]).length !== 0;
  426. var hasRight = this.dom.container.has(this.dom.right[0]).length !== 0;
  427. var buttonsLeft = hasLeft ?
  428. leftOffset.left :
  429. hasRight ?
  430. rightOffset.left :
  431. clearOffset.left;
  432. // Perform the responsive calculations and redraw where necessary
  433. if ((buttonsLeft - valRight < 15 ||
  434. hasLeft && leftOffset.top !== clearOffset.top ||
  435. hasRight && rightOffset.top !== clearOffset.top) &&
  436. !this.dom.container.parent().hasClass(this.classes.vertical)) {
  437. this.dom.container.parent().addClass(this.classes.vertical);
  438. this.s.topGroup.trigger('dtsb-redrawContents');
  439. }
  440. else if (buttonsLeft -
  441. (this.dom.data.offset().left +
  442. this.dom.data.outerWidth(true) +
  443. this.dom.condition.outerWidth(true) +
  444. valWidth) > 15
  445. && this.dom.container.parent().hasClass(this.classes.vertical)) {
  446. this.dom.container.parent().removeClass(this.classes.vertical);
  447. this.s.topGroup.trigger('dtsb-redrawContents');
  448. }
  449. };
  450. /**
  451. * Builds the elements of the dom together
  452. */
  453. Criteria.prototype._buildCriteria = function () {
  454. // Append Titles for select elements
  455. this.dom.data.append(this.dom.dataTitle);
  456. this.dom.condition.append(this.dom.conditionTitle);
  457. // Add elements to container
  458. this.dom.container
  459. .append(this.dom.data)
  460. .append(this.dom.condition);
  461. for (var _i = 0, _a = this.dom.value; _i < _a.length; _i++) {
  462. var val = _a[_i];
  463. val.append(this.dom.valueTitle);
  464. this.dom.container.append(val);
  465. }
  466. // Add buttons to container
  467. this.dom.container
  468. .append(this.dom["delete"])
  469. .append(this.dom.right);
  470. this.setListeners();
  471. };
  472. /**
  473. * Clears the condition select element
  474. */
  475. Criteria.prototype._clearCondition = function () {
  476. this.dom.condition.empty();
  477. this.dom.conditionTitle.attr('selected', 'true').attr('disabled', 'true');
  478. this.dom.condition.prepend(this.dom.conditionTitle).prop('selectedIndex', 0);
  479. this.s.conditions = {};
  480. this.s.condition = undefined;
  481. };
  482. /**
  483. * Clears the value elements
  484. */
  485. Criteria.prototype._clearValue = function () {
  486. if (this.s.condition !== undefined) {
  487. if (this.dom.value.length > 0 && this.dom.value[0] !== undefined) {
  488. var _loop_1 = function (val) {
  489. if (val !== undefined) {
  490. // Timeout is annoying but because of IOS
  491. setTimeout(function () {
  492. val.remove();
  493. }, 50);
  494. }
  495. };
  496. // Remove all of the value elements
  497. for (var _i = 0, _a = this.dom.value; _i < _a.length; _i++) {
  498. var val = _a[_i];
  499. _loop_1(val);
  500. }
  501. }
  502. // Call the init function to get the value elements for this condition
  503. this.dom.value = [].concat(this.s.conditions[this.s.condition].init(this, Criteria.updateListener));
  504. if (this.dom.value.length > 0 && this.dom.value[0] !== undefined) {
  505. this.dom.value[0].insertAfter(this.dom.condition).trigger('dtsb-inserted');
  506. // Insert all of the value elements
  507. for (var i = 1; i < this.dom.value.length; i++) {
  508. this.dom.value[i].insertAfter(this.dom.value[i - 1]).trigger('dtsb-inserted');
  509. }
  510. }
  511. }
  512. else {
  513. var _loop_2 = function (val) {
  514. if (val !== undefined) {
  515. // Timeout is annoying but because of IOS
  516. setTimeout(function () {
  517. val.remove();
  518. }, 50);
  519. }
  520. };
  521. // Remove all of the value elements
  522. for (var _b = 0, _c = this.dom.value; _b < _c.length; _b++) {
  523. var val = _c[_b];
  524. _loop_2(val);
  525. }
  526. // Append the default valueTitle to the default select element
  527. this.dom.valueTitle
  528. .attr('selected', 'true');
  529. this.dom.defaultValue
  530. .append(this.dom.valueTitle)
  531. .insertAfter(this.dom.condition);
  532. }
  533. this.s.value = [];
  534. this.dom.value = [
  535. $$2('<select disabled/>')
  536. .addClass(this.classes.value)
  537. .addClass(this.classes.dropDown)
  538. .addClass(this.classes.italic)
  539. .addClass(this.classes.select)
  540. .append(this.dom.valueTitle.clone())
  541. ];
  542. };
  543. /**
  544. * Gets the options for the column
  545. *
  546. * @returns {object} The options for the column
  547. */
  548. Criteria.prototype._getOptions = function () {
  549. var table = this.s.dt;
  550. return $$2.extend(true, {}, Criteria.defaults, table.settings()[0].aoColumns[this.s.dataIdx].searchBuilder);
  551. };
  552. /**
  553. * Populates the condition dropdown
  554. */
  555. Criteria.prototype._populateCondition = function () {
  556. var conditionOpts = [];
  557. var conditionsLength = Object.keys(this.s.conditions).length;
  558. // If there are no conditions stored then we need to get them from the appropriate type
  559. if (conditionsLength === 0) {
  560. var column = +this.dom.data.children('option:selected').val();
  561. this.s.type = this.s.dt.columns().type().toArray()[column];
  562. // If the column type is unknown, call a draw to try reading it again
  563. if (this.s.type === null) {
  564. this.s.dt.draw(false);
  565. this.setListeners();
  566. this.s.type = this.s.dt.columns().type().toArray()[column];
  567. }
  568. // Enable the condition element
  569. this.dom.condition
  570. .removeAttr('disabled')
  571. .empty()
  572. .append(this.dom.conditionTitle)
  573. .addClass(this.classes.italic);
  574. this.dom.conditionTitle
  575. .attr('selected', 'true');
  576. var decimal = this.s.dt.settings()[0].oLanguage.sDecimal;
  577. // This check is in place for if a custom decimal character is in place
  578. if (decimal !== '' && this.s.type.indexOf(decimal) === this.s.type.length - decimal.length) {
  579. if (this.s.type.includes('num-fmt')) {
  580. this.s.type = this.s.type.replace(decimal, '');
  581. }
  582. else if (this.s.type.includes('num')) {
  583. this.s.type = this.s.type.replace(decimal, '');
  584. }
  585. }
  586. // Select which conditions are going to be used based on the column type
  587. var conditionObj = this.c.conditions[this.s.type] !== undefined ?
  588. this.c.conditions[this.s.type] :
  589. this.s.type.includes('moment') ?
  590. this.c.conditions.moment :
  591. this.s.type.includes('luxon') ?
  592. this.c.conditions.luxon :
  593. this.c.conditions.string;
  594. // If it is a moment format then extract the date format
  595. if (this.s.type.includes('moment')) {
  596. this.s.dateFormat = this.s.type.replace(/moment-/g, '');
  597. }
  598. else if (this.s.type.includes('luxon')) {
  599. this.s.dateFormat = this.s.type.replace(/luxon-/g, '');
  600. }
  601. // Add all of the conditions to the select element
  602. for (var _i = 0, _a = Object.keys(conditionObj); _i < _a.length; _i++) {
  603. var condition = _a[_i];
  604. if (conditionObj[condition] !== null) {
  605. // Serverside processing does not supply the options for the select elements
  606. // Instead input elements need to be used for these instead
  607. if (this.s.dt.page.info().serverSide && conditionObj[condition].init === Criteria.initSelect) {
  608. conditionObj[condition].init = Criteria.initInput;
  609. conditionObj[condition].inputValue = Criteria.inputValueInput;
  610. conditionObj[condition].isInputValid = Criteria.isInputValidInput;
  611. }
  612. this.s.conditions[condition] = conditionObj[condition];
  613. var condName = conditionObj[condition].conditionName;
  614. if (typeof condName === 'function') {
  615. condName = condName(this.s.dt, this.c.i18n);
  616. }
  617. conditionOpts.push($$2('<option>', {
  618. text: condName,
  619. value: condition
  620. })
  621. .addClass(this.classes.option)
  622. .addClass(this.classes.notItalic));
  623. }
  624. }
  625. }
  626. // Otherwise we can just load them in
  627. else if (conditionsLength > 0) {
  628. this.dom.condition.empty().removeAttr('disabled').addClass(this.classes.italic);
  629. for (var _b = 0, _c = Object.keys(this.s.conditions); _b < _c.length; _b++) {
  630. var condition = _c[_b];
  631. var condName = this.s.conditions[condition].conditionName;
  632. if (typeof condName === 'function') {
  633. condName = condName(this.s.dt, this.c.i18n);
  634. }
  635. var newOpt = $$2('<option>', {
  636. text: condName,
  637. value: condition
  638. })
  639. .addClass(this.classes.option)
  640. .addClass(this.classes.notItalic);
  641. if (this.s.condition !== undefined && this.s.condition === condName) {
  642. newOpt.attr('selected', true);
  643. this.dom.condition.removeClass(this.classes.italic);
  644. }
  645. conditionOpts.push(newOpt);
  646. }
  647. }
  648. else {
  649. this.dom.condition
  650. .attr('disabled', 'true')
  651. .addClass(this.classes.italic);
  652. return;
  653. }
  654. for (var _d = 0, conditionOpts_1 = conditionOpts; _d < conditionOpts_1.length; _d++) {
  655. var opt = conditionOpts_1[_d];
  656. this.dom.condition.append(opt);
  657. }
  658. this.dom.condition.prop('selectedIndex', 0);
  659. };
  660. /**
  661. * Populates the data select element
  662. */
  663. Criteria.prototype._populateData = function () {
  664. var _this = this;
  665. this.dom.data.empty().append(this.dom.dataTitle);
  666. // If there are no datas stored then we need to get them from the table
  667. if (this.s.dataPoints.length === 0) {
  668. this.s.dt.columns().every(function (index) {
  669. // Need to check that the column can be filtered on before adding it
  670. if (_this.c.columns === true ||
  671. _this.s.dt.columns(_this.c.columns).indexes().toArray().includes(index)) {
  672. var found = false;
  673. for (var _i = 0, _a = _this.s.dataPoints; _i < _a.length; _i++) {
  674. var val = _a[_i];
  675. if (val.index === index) {
  676. found = true;
  677. break;
  678. }
  679. }
  680. if (!found) {
  681. var col = _this.s.dt.settings()[0].aoColumns[index];
  682. var opt = {
  683. index: index,
  684. origData: col.data,
  685. text: (col.searchBuilderTitle === undefined ?
  686. col.sTitle :
  687. col.searchBuilderTitle).replace(/(<([^>]+)>)/ig, '')
  688. };
  689. _this.s.dataPoints.push(opt);
  690. _this.dom.data.append($$2('<option>', {
  691. text: opt.text,
  692. value: opt.index
  693. })
  694. .addClass(_this.classes.option)
  695. .addClass(_this.classes.notItalic)
  696. .attr('origData', col.data));
  697. }
  698. }
  699. });
  700. }
  701. // Otherwise we can just load them in
  702. else {
  703. var _loop_3 = function (data) {
  704. this_1.s.dt.columns().every(function (index) {
  705. var col = _this.s.dt.settings()[0].aoColumns[index];
  706. if ((col.searchBuilderTitle === undefined ?
  707. col.sTitle :
  708. col.searchBuilderTitle).replace(/(<([^>]+)>)/ig, '') === data.text) {
  709. data.index = index;
  710. data.origData = col.data;
  711. }
  712. });
  713. var newOpt = $$2('<option>', {
  714. text: data.text.replace(/(<([^>]+)>)/ig, ''),
  715. value: data.index
  716. })
  717. .addClass(this_1.classes.option)
  718. .addClass(this_1.classes.notItalic)
  719. .attr('origData', data.origData);
  720. if (this_1.s.data === data.text) {
  721. this_1.s.dataIdx = data.index;
  722. newOpt.attr('selected', true);
  723. this_1.dom.data.removeClass(this_1.classes.italic);
  724. }
  725. this_1.dom.data.append(newOpt);
  726. };
  727. var this_1 = this;
  728. for (var _i = 0, _a = this.s.dataPoints; _i < _a.length; _i++) {
  729. var data = _a[_i];
  730. _loop_3(data);
  731. }
  732. }
  733. };
  734. /**
  735. * Populates the Value select element
  736. *
  737. * @param loadedCriteria optional, used to reload criteria from predefined filters
  738. */
  739. Criteria.prototype._populateValue = function (loadedCriteria) {
  740. var _this = this;
  741. var prevFilled = this.s.filled;
  742. this.s.filled = false;
  743. // Remove any previous value elements
  744. // Timeout is annoying but because of IOS
  745. setTimeout(function () {
  746. _this.dom.defaultValue.remove();
  747. }, 50);
  748. var _loop_4 = function (val) {
  749. // Timeout is annoying but because of IOS
  750. setTimeout(function () {
  751. if (val !== undefined) {
  752. val.remove();
  753. }
  754. }, 50);
  755. };
  756. for (var _i = 0, _a = this.dom.value; _i < _a.length; _i++) {
  757. var val = _a[_i];
  758. _loop_4(val);
  759. }
  760. var children = this.dom.container.children();
  761. if (children.length > 3) {
  762. for (var i = 2; i < children.length - 1; i++) {
  763. $$2(children[i]).remove();
  764. }
  765. }
  766. // Find the column with the title matching the data for the criteria and take note of the index
  767. if (loadedCriteria !== undefined) {
  768. this.s.dt.columns().every(function (index) {
  769. if (_this.s.dt.settings()[0].aoColumns[index].sTitle === loadedCriteria.data) {
  770. _this.s.dataIdx = index;
  771. }
  772. });
  773. }
  774. // Initialise the value elements based on the condition
  775. this.dom.value = [].concat(this.s.conditions[this.s.condition].init(this, Criteria.updateListener, loadedCriteria !== undefined ? loadedCriteria.value : undefined));
  776. if (loadedCriteria !== undefined && loadedCriteria.value !== undefined) {
  777. this.s.value = loadedCriteria.value;
  778. }
  779. // Insert value elements and trigger the inserted event
  780. if (this.dom.value[0] !== undefined) {
  781. this.dom.value[0]
  782. .insertAfter(this.dom.condition)
  783. .trigger('dtsb-inserted');
  784. }
  785. for (var i = 1; i < this.dom.value.length; i++) {
  786. this.dom.value[i]
  787. .insertAfter(this.dom.value[i - 1])
  788. .trigger('dtsb-inserted');
  789. }
  790. // Check if the criteria can be used in a search
  791. this.s.filled = this.s.conditions[this.s.condition].isInputValid(this.dom.value, this);
  792. this.setListeners();
  793. // If it can and this is different to before then trigger a draw
  794. if (prevFilled !== this.s.filled) {
  795. this.s.dt.draw();
  796. this.setListeners();
  797. }
  798. };
  799. /**
  800. * Provides throttling capabilities to SearchBuilder without having to use dt's _fnThrottle function
  801. * This is because that function is not quite suitable for our needs as it runs initially rather than waiting
  802. *
  803. * @param args arguments supplied to the throttle function
  804. * @returns Function that is to be run that implements the throttling
  805. */
  806. Criteria.prototype._throttle = function (fn, frequency) {
  807. if (frequency === void 0) { frequency = 200; }
  808. var last = null;
  809. var timer = null;
  810. var that = this;
  811. if (frequency === null) {
  812. frequency = 200;
  813. }
  814. return function () {
  815. var args = [];
  816. for (var _i = 0; _i < arguments.length; _i++) {
  817. args[_i] = arguments[_i];
  818. }
  819. var now = +new Date();
  820. if (last !== null && now < last + frequency) {
  821. clearTimeout(timer);
  822. }
  823. else {
  824. last = now;
  825. }
  826. timer = setTimeout(function () {
  827. last = null;
  828. fn.apply(that, args);
  829. }, frequency);
  830. };
  831. };
  832. Criteria.version = '1.1.0';
  833. Criteria.classes = {
  834. button: 'dtsb-button',
  835. buttonContainer: 'dtsb-buttonContainer',
  836. condition: 'dtsb-condition',
  837. container: 'dtsb-criteria',
  838. data: 'dtsb-data',
  839. "delete": 'dtsb-delete',
  840. dropDown: 'dtsb-dropDown',
  841. greyscale: 'dtsb-greyscale',
  842. input: 'dtsb-input',
  843. italic: 'dtsb-italic',
  844. joiner: 'dtsp-joiner',
  845. left: 'dtsb-left',
  846. notItalic: 'dtsb-notItalic',
  847. option: 'dtsb-option',
  848. right: 'dtsb-right',
  849. select: 'dtsb-select',
  850. value: 'dtsb-value',
  851. vertical: 'dtsb-vertical'
  852. };
  853. /**
  854. * Default initialisation function for select conditions
  855. */
  856. Criteria.initSelect = function (that, fn, preDefined, array) {
  857. if (preDefined === void 0) { preDefined = null; }
  858. if (array === void 0) { array = false; }
  859. var column = that.dom.data.children('option:selected').val();
  860. var indexArray = that.s.dt.rows().indexes().toArray();
  861. var settings = that.s.dt.settings()[0];
  862. // Declare select element to be used with all of the default classes and listeners.
  863. var el = $$2('<select/>')
  864. .addClass(Criteria.classes.value)
  865. .addClass(Criteria.classes.dropDown)
  866. .addClass(Criteria.classes.italic)
  867. .addClass(Criteria.classes.select)
  868. .append(that.dom.valueTitle)
  869. .on('change', function () {
  870. $$2(this).removeClass(Criteria.classes.italic);
  871. fn(that, this);
  872. });
  873. if (that.c.greyscale) {
  874. el.addClass(Criteria.classes.greyscale);
  875. }
  876. var added = [];
  877. var options = [];
  878. // Add all of the options from the table to the select element.
  879. // Only add one option for each possible value
  880. for (var _i = 0, indexArray_1 = indexArray; _i < indexArray_1.length; _i++) {
  881. var index = indexArray_1[_i];
  882. var filter = settings.oApi._fnGetCellData(settings, index, column, typeof that.c.orthogonal === 'string' ?
  883. that.c.orthogonal :
  884. that.c.orthogonal.search);
  885. var value = {
  886. filter: typeof filter === 'string' ?
  887. filter.replace(/[\r\n\u2028]/g, ' ') : // Need to replace certain characters to match search values
  888. filter,
  889. index: index,
  890. text: settings.oApi._fnGetCellData(settings, index, column, typeof that.c.orthogonal === 'string' ?
  891. that.c.orthogonal :
  892. that.c.orthogonal.display)
  893. };
  894. // If we are dealing with an array type, either make sure we are working with arrays, or sort them
  895. if (that.s.type === 'array') {
  896. value.filter = !Array.isArray(value.filter) ?
  897. [value.filter] :
  898. value.filter = value.filter.sort();
  899. value.text = !Array.isArray(value.text) ?
  900. [value.text] :
  901. value.text = value.text.sort();
  902. }
  903. // Function to add an option to the select element
  904. var addOption = function (filt, text) {
  905. // Add text and value, stripping out any html if that is the column type
  906. var opt = $$2('<option>', {
  907. type: Array.isArray(filt) ? 'Array' : 'String',
  908. value: that.s.type.includes('html') && filt !== null && typeof filt === 'string' ?
  909. filt.replace(/(<([^>]+)>)/ig, '') :
  910. filt
  911. })
  912. .addClass(that.classes.option)
  913. .addClass(that.classes.notItalic)
  914. // Have to add the text this way so that special html characters are not escaped - &amp; etc.
  915. .html(typeof text === 'string' ?
  916. text.replace(/(<([^>]+)>)/ig, '') :
  917. text);
  918. var val = opt.val();
  919. // Check that this value has not already been added
  920. if (added.indexOf(val) === -1) {
  921. added.push(val);
  922. options.push(opt);
  923. if (preDefined !== null && Array.isArray(preDefined[0])) {
  924. preDefined[0] = preDefined[0].sort().join(',');
  925. }
  926. // If this value was previously selected as indicated by preDefined, then select it again
  927. if (preDefined !== null && opt.val() === preDefined[0]) {
  928. opt.attr('selected', true);
  929. el.removeClass(Criteria.classes.italic);
  930. }
  931. }
  932. };
  933. // If this is to add the individual values within the array we need to loop over the array
  934. if (array) {
  935. for (var i = 0; i < value.filter.length; i++) {
  936. addOption(value.filter[i], value.text[i]);
  937. }
  938. }
  939. // Otherwise the value that is in the cell is to be added
  940. else {
  941. addOption(value.filter, value.text);
  942. }
  943. }
  944. options.sort(function (a, b) {
  945. if (that.s.type === 'array' ||
  946. that.s.type === 'string' ||
  947. that.s.type === 'html') {
  948. if (a.val() < b.val()) {
  949. return -1;
  950. }
  951. else if (a.val() > b.val()) {
  952. return 1;
  953. }
  954. else {
  955. return 0;
  956. }
  957. }
  958. else if (that.s.type === 'num' ||
  959. that.s.type === 'html-num') {
  960. if (+a.val().replace(/(<([^>]+)>)/ig, '') < +b.val().replace(/(<([^>]+)>)/ig, '')) {
  961. return -1;
  962. }
  963. else if (+a.val().replace(/(<([^>]+)>)/ig, '') > +b.val().replace(/(<([^>]+)>)/ig, '')) {
  964. return 1;
  965. }
  966. else {
  967. return 0;
  968. }
  969. }
  970. else if (that.s.type === 'num-fmt' || that.s.type === 'html-num-fmt') {
  971. if (+a.val().replace(/[^0-9.]/g, '') < +b.val().replace(/[^0-9.]/g, '')) {
  972. return -1;
  973. }
  974. else if (+a.val().replace(/[^0-9.]/g, '') > +b.val().replace(/[^0-9.]/g, '')) {
  975. return 1;
  976. }
  977. else {
  978. return 0;
  979. }
  980. }
  981. });
  982. for (var _a = 0, options_1 = options; _a < options_1.length; _a++) {
  983. var opt = options_1[_a];
  984. el.append(opt);
  985. }
  986. return el;
  987. };
  988. /**
  989. * Default initialisation function for select array conditions
  990. *
  991. * This exists because there needs to be different select functionality for contains/without and equals/not
  992. */
  993. Criteria.initSelectArray = function (that, fn, preDefined) {
  994. if (preDefined === void 0) { preDefined = null; }
  995. return Criteria.initSelect(that, fn, preDefined, true);
  996. };
  997. /**
  998. * Default initialisation function for input conditions
  999. */
  1000. Criteria.initInput = function (that, fn, preDefined) {
  1001. if (preDefined === void 0) { preDefined = null; }
  1002. // Declare the input element
  1003. var searchDelay = that.s.dt.settings()[0].searchDelay;
  1004. var el = $$2('<input/>')
  1005. .addClass(Criteria.classes.value)
  1006. .addClass(Criteria.classes.input)
  1007. .on('input keypress', that._throttle(function (e) {
  1008. var code = e.keyCode || e.which;
  1009. if (!that.c.enterSearch || code === 13) {
  1010. return fn(that, this);
  1011. }
  1012. }, searchDelay === null ? 100 : searchDelay));
  1013. if (that.c.greyscale) {
  1014. el.addClass(Criteria.classes.greyscale);
  1015. }
  1016. // If there is a preDefined value then add it
  1017. if (preDefined !== null) {
  1018. el.val(preDefined[0]);
  1019. }
  1020. // This is add responsive functionality to the logic button without redrawing everything else
  1021. that.s.dt.one('draw', function () {
  1022. that.s.topGroup.trigger('dtsb-redrawLogic');
  1023. });
  1024. return el;
  1025. };
  1026. /**
  1027. * Default initialisation function for conditions requiring 2 inputs
  1028. */
  1029. Criteria.init2Input = function (that, fn, preDefined) {
  1030. if (preDefined === void 0) { preDefined = null; }
  1031. // Declare all of the necessary jQuery elements
  1032. var searchDelay = that.s.dt.settings()[0].searchDelay;
  1033. var els = [
  1034. $$2('<input/>')
  1035. .addClass(Criteria.classes.value)
  1036. .addClass(Criteria.classes.input)
  1037. .on('input keypress', that._throttle(function (e) {
  1038. var code = e.keyCode || e.which;
  1039. if (!that.c.enterSearch || code === 13) {
  1040. return fn(that, this);
  1041. }
  1042. }, searchDelay === null ? 100 : searchDelay)),
  1043. $$2('<span>')
  1044. .addClass(that.classes.joiner)
  1045. .text(that.s.dt.i18n('searchBuilder.valueJoiner', that.c.i18n.valueJoiner)),
  1046. $$2('<input/>')
  1047. .addClass(Criteria.classes.value)
  1048. .addClass(Criteria.classes.input)
  1049. .on('input keypress', that._throttle(function (e) {
  1050. var code = e.keyCode || e.which;
  1051. if (!that.c.enterSearch || code === 13) {
  1052. return fn(that, this);
  1053. }
  1054. }, searchDelay === null ? 100 : searchDelay))
  1055. ];
  1056. if (that.c.greyscale) {
  1057. els[0].addClass(Criteria.classes.greyscale);
  1058. els[2].addClass(Criteria.classes.greyscale);
  1059. }
  1060. // If there is a preDefined value then add it
  1061. if (preDefined !== null) {
  1062. els[0].val(preDefined[0]);
  1063. els[2].val(preDefined[1]);
  1064. }
  1065. // This is add responsive functionality to the logic button without redrawing everything else
  1066. that.s.dt.one('draw', function () {
  1067. that.s.topGroup.trigger('dtsb-redrawLogic');
  1068. });
  1069. return els;
  1070. };
  1071. /**
  1072. * Default initialisation function for date conditions
  1073. */
  1074. Criteria.initDate = function (that, fn, preDefined) {
  1075. if (preDefined === void 0) { preDefined = null; }
  1076. var searchDelay = that.s.dt.settings()[0].searchDelay;
  1077. // Declare date element using DataTables dateTime plugin
  1078. var el = $$2('<input/>')
  1079. .addClass(Criteria.classes.value)
  1080. .addClass(Criteria.classes.input)
  1081. .dtDateTime({
  1082. attachTo: 'input',
  1083. format: that.s.dateFormat ? that.s.dateFormat : undefined
  1084. })
  1085. .on('change', that._throttle(function () {
  1086. return fn(that, this);
  1087. }, searchDelay === null ? 100 : searchDelay))
  1088. .on('input keypress', that.c.enterSearch ?
  1089. function (e) {
  1090. that._throttle(function () {
  1091. var code = e.keyCode || e.which;
  1092. if (code === 13) {
  1093. return fn(that, this);
  1094. }
  1095. }, searchDelay === null ? 100 : searchDelay);
  1096. } :
  1097. that._throttle(function () {
  1098. return fn(that, this);
  1099. }, searchDelay === null ? 100 : searchDelay));
  1100. if (that.c.greyscale) {
  1101. el.addClass(Criteria.classes.greyscale);
  1102. }
  1103. // If there is a preDefined value then add it
  1104. if (preDefined !== null) {
  1105. el.val(preDefined[0]);
  1106. }
  1107. // This is add responsive functionality to the logic button without redrawing everything else
  1108. that.s.dt.one('draw', function () {
  1109. that.s.topGroup.trigger('dtsb-redrawLogic');
  1110. });
  1111. return el;
  1112. };
  1113. Criteria.initNoValue = function (that) {
  1114. // This is add responsive functionality to the logic button without redrawing everything else
  1115. that.s.dt.one('draw', function () {
  1116. that.s.topGroup.trigger('dtsb-redrawLogic');
  1117. });
  1118. };
  1119. Criteria.init2Date = function (that, fn, preDefined) {
  1120. var _this = this;
  1121. if (preDefined === void 0) { preDefined = null; }
  1122. var searchDelay = that.s.dt.settings()[0].searchDelay;
  1123. // Declare all of the date elements that are required using DataTables dateTime plugin
  1124. var els = [
  1125. $$2('<input/>')
  1126. .addClass(Criteria.classes.value)
  1127. .addClass(Criteria.classes.input)
  1128. .dtDateTime({
  1129. attachTo: 'input',
  1130. format: that.s.dateFormat ? that.s.dateFormat : undefined
  1131. })
  1132. .on('change', searchDelay !== null ?
  1133. that.s.dt.settings()[0].oApi._fnThrottle(function () {
  1134. return fn(that, this);
  1135. }, searchDelay) :
  1136. function () {
  1137. fn(that, _this);
  1138. })
  1139. .on('input keypress', !that.c.enterSearch && searchDelay !== null ?
  1140. that.s.dt.settings()[0].oApi._fnThrottle(function () {
  1141. return fn(that, this);
  1142. }, searchDelay) :
  1143. that.c.enterSearch ?
  1144. function (e) {
  1145. var code = e.keyCode || e.which;
  1146. if (code === 13) {
  1147. fn(that, _this);
  1148. }
  1149. } :
  1150. function () {
  1151. fn(that, _this);
  1152. }),
  1153. $$2('<span>')
  1154. .addClass(that.classes.joiner)
  1155. .text(that.s.dt.i18n('searchBuilder.valueJoiner', that.c.i18n.valueJoiner)),
  1156. $$2('<input/>')
  1157. .addClass(Criteria.classes.value)
  1158. .addClass(Criteria.classes.input)
  1159. .dtDateTime({
  1160. attachTo: 'input',
  1161. format: that.s.dateFormat ? that.s.dateFormat : undefined
  1162. })
  1163. .on('change', searchDelay !== null ?
  1164. that.s.dt.settings()[0].oApi._fnThrottle(function () {
  1165. return fn(that, this);
  1166. }, searchDelay) :
  1167. function () {
  1168. fn(that, _this);
  1169. })
  1170. .on('input keypress', !that.c.enterSearch && searchDelay !== null ?
  1171. that.s.dt.settings()[0].oApi._fnThrottle(function () {
  1172. return fn(that, this);
  1173. }, searchDelay) :
  1174. that.c.enterSearch ?
  1175. function (e) {
  1176. var code = e.keyCode || e.which;
  1177. if (code === 13) {
  1178. fn(that, _this);
  1179. }
  1180. } :
  1181. function () {
  1182. fn(that, _this);
  1183. })
  1184. ];
  1185. if (that.c.greyscale) {
  1186. els[0].addClass(Criteria.classes.greyscale);
  1187. els[2].addClass(Criteria.classes.greyscale);
  1188. }
  1189. // If there are and preDefined values then add them
  1190. if (preDefined !== null && preDefined.length > 0) {
  1191. els[0].val(preDefined[0]);
  1192. els[2].val(preDefined[1]);
  1193. }
  1194. // This is add responsive functionality to the logic button without redrawing everything else
  1195. that.s.dt.one('draw', function () {
  1196. that.s.topGroup.trigger('dtsb-redrawLogic');
  1197. });
  1198. return els;
  1199. };
  1200. /**
  1201. * Default function for select elements to validate condition
  1202. */
  1203. Criteria.isInputValidSelect = function (el) {
  1204. var allFilled = true;
  1205. // Check each element to make sure that the selections are valid
  1206. for (var _i = 0, el_1 = el; _i < el_1.length; _i++) {
  1207. var element = el_1[_i];
  1208. if (element.children('option:selected').length ===
  1209. element.children('option').length -
  1210. element.children('option.' + Criteria.classes.notItalic).length &&
  1211. element.children('option:selected').length === 1 &&
  1212. element.children('option:selected')[0] === element.children('option:hidden')[0]) {
  1213. allFilled = false;
  1214. }
  1215. }
  1216. return allFilled;
  1217. };
  1218. /**
  1219. * Default function for input and date elements to validate condition
  1220. */
  1221. Criteria.isInputValidInput = function (el) {
  1222. var allFilled = true;
  1223. // Check each element to make sure that the inputs are valid
  1224. for (var _i = 0, el_2 = el; _i < el_2.length; _i++) {
  1225. var element = el_2[_i];
  1226. if (element.is('input') && element.val().length === 0) {
  1227. allFilled = false;
  1228. }
  1229. }
  1230. return allFilled;
  1231. };
  1232. /**
  1233. * Default function for getting select conditions
  1234. */
  1235. Criteria.inputValueSelect = function (el) {
  1236. var values = [];
  1237. // Go through the select elements and push each selected option to the return array
  1238. for (var _i = 0, el_3 = el; _i < el_3.length; _i++) {
  1239. var element = el_3[_i];
  1240. if (element.is('select')) {
  1241. var val = element.children('option:selected').val();
  1242. // If the type of the option is an array we need to split it up and sort it
  1243. values.push(element.children('option:selected').attr('type') === 'Array' ?
  1244. val.split(',').sort() :
  1245. val);
  1246. }
  1247. }
  1248. return values;
  1249. };
  1250. /**
  1251. * Default function for getting input conditions
  1252. */
  1253. Criteria.inputValueInput = function (el) {
  1254. var values = [];
  1255. // Go through the input elements and push each value to the return array
  1256. for (var _i = 0, el_4 = el; _i < el_4.length; _i++) {
  1257. var element = el_4[_i];
  1258. if (element.is('input')) {
  1259. values.push(element.val());
  1260. }
  1261. }
  1262. return values;
  1263. };
  1264. /**
  1265. * Function that is run on each element as a call back when a search should be triggered
  1266. */
  1267. Criteria.updateListener = function (that, el) {
  1268. // When the value is changed the criteria is now complete so can be included in searches
  1269. // Get the condition from the map based on the key that has been selected for the condition
  1270. var condition = that.s.conditions[that.s.condition];
  1271. that.s.filled = condition.isInputValid(that.dom.value, that);
  1272. that.s.value = condition.inputValue(that.dom.value, that);
  1273. if (!that.s.filled) {
  1274. that.s.dt.draw();
  1275. return;
  1276. }
  1277. if (!Array.isArray(that.s.value)) {
  1278. that.s.value = [that.s.value];
  1279. }
  1280. for (var i = 0; i < that.s.value.length; i++) {
  1281. // If the value is an array we need to sort it
  1282. if (Array.isArray(that.s.value[i])) {
  1283. that.s.value[i].sort();
  1284. }
  1285. // Otherwise replace the decimal place character for i18n
  1286. else if (that.s.type.includes('num') &&
  1287. (that.s.dt.settings()[0].oLanguage.sDecimal !== '' ||
  1288. that.s.dt.settings()[0].oLanguage.sThousands !== '')) {
  1289. var splitRD = [that.s.value[i].toString()];
  1290. if (that.s.dt.settings()[0].oLanguage.sDecimal !== '') {
  1291. splitRD = that.s.value[i].split(that.s.dt.settings()[0].oLanguage.sDecimal);
  1292. }
  1293. if (that.s.dt.settings()[0].oLanguage.sThousands !== '') {
  1294. for (var j = 0; j < splitRD.length; j++) {
  1295. splitRD[j] = splitRD[j].replace(that.s.dt.settings()[0].oLanguage.sThousands, ',');
  1296. }
  1297. }
  1298. that.s.value[i] = splitRD.join('.');
  1299. }
  1300. }
  1301. // Take note of the cursor position so that we can refocus there later
  1302. var idx = null;
  1303. var cursorPos = null;
  1304. for (var i = 0; i < that.dom.value.length; i++) {
  1305. if (el === that.dom.value[i][0]) {
  1306. idx = i;
  1307. if (el.selectionStart !== undefined) {
  1308. cursorPos = el.selectionStart;
  1309. }
  1310. }
  1311. }
  1312. // Trigger a search
  1313. that.s.dt.draw();
  1314. // Refocus the element and set the correct cursor position
  1315. if (idx !== null) {
  1316. that.dom.value[idx].removeClass(that.classes.italic);
  1317. that.dom.value[idx].focus();
  1318. if (cursorPos !== null) {
  1319. that.dom.value[idx][0].setSelectionRange(cursorPos, cursorPos);
  1320. }
  1321. }
  1322. };
  1323. // The order of the conditions will make eslint sad :(
  1324. // Has to be in this order so that they are displayed correctly in select elements
  1325. // Also have to disable member ordering for this as the private methods used are not yet declared otherwise
  1326. // eslint-disable-next-line @typescript-eslint/member-ordering
  1327. Criteria.dateConditions = {
  1328. '=': {
  1329. conditionName: function (dt, i18n) {
  1330. return dt.i18n('searchBuilder.conditions.date.equals', i18n.conditions.date.equals);
  1331. },
  1332. init: Criteria.initDate,
  1333. inputValue: Criteria.inputValueInput,
  1334. isInputValid: Criteria.isInputValidInput,
  1335. search: function (value, comparison) {
  1336. value = value.replace(/(\/|-|,)/g, '-');
  1337. return value === comparison[0];
  1338. }
  1339. },
  1340. // eslint-disable-next-line sort-keys
  1341. '!=': {
  1342. conditionName: function (dt, i18n) {
  1343. return dt.i18n('searchBuilder.conditions.date.not', i18n.conditions.date.not);
  1344. },
  1345. init: Criteria.initDate,
  1346. inputValue: Criteria.inputValueInput,
  1347. isInputValid: Criteria.isInputValidInput,
  1348. search: function (value, comparison) {
  1349. value = value.replace(/(\/|-|,)/g, '-');
  1350. return value !== comparison[0];
  1351. }
  1352. },
  1353. '<': {
  1354. conditionName: function (dt, i18n) {
  1355. return dt.i18n('searchBuilder.conditions.date.before', i18n.conditions.date.before);
  1356. },
  1357. init: Criteria.initDate,
  1358. inputValue: Criteria.inputValueInput,
  1359. isInputValid: Criteria.isInputValidInput,
  1360. search: function (value, comparison) {
  1361. value = value.replace(/(\/|-|,)/g, '-');
  1362. return value < comparison[0];
  1363. }
  1364. },
  1365. '>': {
  1366. conditionName: function (dt, i18n) {
  1367. return dt.i18n('searchBuilder.conditions.date.after', i18n.conditions.date.after);
  1368. },
  1369. init: Criteria.initDate,
  1370. inputValue: Criteria.inputValueInput,
  1371. isInputValid: Criteria.isInputValidInput,
  1372. search: function (value, comparison) {
  1373. value = value.replace(/(\/|-|,)/g, '-');
  1374. return value > comparison[0];
  1375. }
  1376. },
  1377. 'between': {
  1378. conditionName: function (dt, i18n) {
  1379. return dt.i18n('searchBuilder.conditions.date.between', i18n.conditions.date.between);
  1380. },
  1381. init: Criteria.init2Date,
  1382. inputValue: Criteria.inputValueInput,
  1383. isInputValid: Criteria.isInputValidInput,
  1384. search: function (value, comparison) {
  1385. value = value.replace(/(\/|-|,)/g, '-');
  1386. if (comparison[0] < comparison[1]) {
  1387. return comparison[0] <= value && value <= comparison[1];
  1388. }
  1389. else {
  1390. return comparison[1] <= value && value <= comparison[0];
  1391. }
  1392. }
  1393. },
  1394. // eslint-disable-next-line sort-keys
  1395. '!between': {
  1396. conditionName: function (dt, i18n) {
  1397. return dt.i18n('searchBuilder.conditions.date.notBetween', i18n.conditions.date.notBetween);
  1398. },
  1399. init: Criteria.init2Date,
  1400. inputValue: Criteria.inputValueInput,
  1401. isInputValid: Criteria.isInputValidInput,
  1402. search: function (value, comparison) {
  1403. value = value.replace(/(\/|-|,)/g, '-');
  1404. if (comparison[0] < comparison[1]) {
  1405. return !(comparison[0] <= value && value <= comparison[1]);
  1406. }
  1407. else {
  1408. return !(comparison[1] <= value && value <= comparison[0]);
  1409. }
  1410. }
  1411. },
  1412. 'null': {
  1413. conditionName: function (dt, i18n) {
  1414. return dt.i18n('searchBuilder.conditions.date.empty', i18n.conditions.date.empty);
  1415. },
  1416. init: Criteria.initNoValue,
  1417. inputValue: function () {
  1418. return;
  1419. },
  1420. isInputValid: function () {
  1421. return true;
  1422. },
  1423. search: function (value) {
  1424. return value === null || value === undefined || value.length === 0;
  1425. }
  1426. },
  1427. // eslint-disable-next-line sort-keys
  1428. '!null': {
  1429. conditionName: function (dt, i18n) {
  1430. return dt.i18n('searchBuilder.conditions.date.notEmpty', i18n.conditions.date.notEmpty);
  1431. },
  1432. init: Criteria.initNoValue,
  1433. inputValue: function () {
  1434. return;
  1435. },
  1436. isInputValid: function () {
  1437. return true;
  1438. },
  1439. search: function (value) {
  1440. return !(value === null || value === undefined || value.length === 0);
  1441. }
  1442. }
  1443. };
  1444. // The order of the conditions will make eslint sad :(
  1445. // Has to be in this order so that they are displayed correctly in select elements
  1446. // Also have to disable member ordering for this as the private methods used are not yet declared otherwise
  1447. // eslint-disable-next-line @typescript-eslint/member-ordering
  1448. Criteria.momentDateConditions = {
  1449. '=': {
  1450. conditionName: function (dt, i18n) {
  1451. return dt.i18n('searchBuilder.conditions.date.equals', i18n.conditions.date.equals);
  1452. },
  1453. init: Criteria.initDate,
  1454. inputValue: Criteria.inputValueInput,
  1455. isInputValid: Criteria.isInputValidInput,
  1456. search: function (value, comparison, that) {
  1457. return moment(value, that.s.dateFormat).valueOf() ===
  1458. moment(comparison[0], that.s.dateFormat).valueOf();
  1459. }
  1460. },
  1461. // eslint-disable-next-line sort-keys
  1462. '!=': {
  1463. conditionName: function (dt, i18n) {
  1464. return dt.i18n('searchBuilder.conditions.date.not', i18n.conditions.date.not);
  1465. },
  1466. init: Criteria.initDate,
  1467. inputValue: Criteria.inputValueInput,
  1468. isInputValid: Criteria.isInputValidInput,
  1469. search: function (value, comparison, that) {
  1470. return moment(value, that.s.dateFormat).valueOf() !==
  1471. moment(comparison[0], that.s.dateFormat).valueOf();
  1472. }
  1473. },
  1474. '<': {
  1475. conditionName: function (dt, i18n) {
  1476. return dt.i18n('searchBuilder.conditions.date.before', i18n.conditions.date.before);
  1477. },
  1478. init: Criteria.initDate,
  1479. inputValue: Criteria.inputValueInput,
  1480. isInputValid: Criteria.isInputValidInput,
  1481. search: function (value, comparison, that) {
  1482. return moment(value, that.s.dateFormat).valueOf() < moment(comparison[0], that.s.dateFormat).valueOf();
  1483. }
  1484. },
  1485. '>': {
  1486. conditionName: function (dt, i18n) {
  1487. return dt.i18n('searchBuilder.conditions.date.after', i18n.conditions.date.after);
  1488. },
  1489. init: Criteria.initDate,
  1490. inputValue: Criteria.inputValueInput,
  1491. isInputValid: Criteria.isInputValidInput,
  1492. search: function (value, comparison, that) {
  1493. return moment(value, that.s.dateFormat).valueOf() > moment(comparison[0], that.s.dateFormat).valueOf();
  1494. }
  1495. },
  1496. 'between': {
  1497. conditionName: function (dt, i18n) {
  1498. return dt.i18n('searchBuilder.conditions.date.between', i18n.conditions.date.between);
  1499. },
  1500. init: Criteria.init2Date,
  1501. inputValue: Criteria.inputValueInput,
  1502. isInputValid: Criteria.isInputValidInput,
  1503. search: function (value, comparison, that) {
  1504. var val = moment(value, that.s.dateFormat).valueOf();
  1505. var comp0 = moment(comparison[0], that.s.dateFormat).valueOf();
  1506. var comp1 = moment(comparison[1], that.s.dateFormat).valueOf();
  1507. if (comp0 < comp1) {
  1508. return comp0 <= val && val <= comp1;
  1509. }
  1510. else {
  1511. return comp1 <= val && val <= comp0;
  1512. }
  1513. }
  1514. },
  1515. // eslint-disable-next-line sort-keys
  1516. '!between': {
  1517. conditionName: function (dt, i18n) {
  1518. return dt.i18n('searchBuilder.conditions.date.notBetween', i18n.conditions.date.notBetween);
  1519. },
  1520. init: Criteria.init2Date,
  1521. inputValue: Criteria.inputValueInput,
  1522. isInputValid: Criteria.isInputValidInput,
  1523. search: function (value, comparison, that) {
  1524. var val = moment(value, that.s.dateFormat).valueOf();
  1525. var comp0 = moment(comparison[0], that.s.dateFormat).valueOf();
  1526. var comp1 = moment(comparison[1], that.s.dateFormat).valueOf();
  1527. if (comp0 < comp1) {
  1528. return !(+comp0 <= +val && +val <= +comp1);
  1529. }
  1530. else {
  1531. return !(+comp1 <= +val && +val <= +comp0);
  1532. }
  1533. }
  1534. },
  1535. 'null': {
  1536. conditionName: function (dt, i18n) {
  1537. return dt.i18n('searchBuilder.conditions.date.empty', i18n.conditions.date.empty);
  1538. },
  1539. init: Criteria.initNoValue,
  1540. inputValue: function () {
  1541. return;
  1542. },
  1543. isInputValid: function () {
  1544. return true;
  1545. },
  1546. search: function (value) {
  1547. return value === null || value === undefined || value.length === 0;
  1548. }
  1549. },
  1550. // eslint-disable-next-line sort-keys
  1551. '!null': {
  1552. conditionName: function (dt, i18n) {
  1553. return dt.i18n('searchBuilder.conditions.date.notEmpty', i18n.conditions.date.notEmpty);
  1554. },
  1555. init: Criteria.initNoValue,
  1556. inputValue: function () {
  1557. return;
  1558. },
  1559. isInputValid: function () {
  1560. return true;
  1561. },
  1562. search: function (value) {
  1563. return !(value === null || value === undefined || value.length === 0);
  1564. }
  1565. }
  1566. };
  1567. // The order of the conditions will make eslint sad :(
  1568. // Has to be in this order so that they are displayed correctly in select elements
  1569. // Also have to disable member ordering for this as the private methods used are not yet declared otherwise
  1570. // eslint-disable-next-line @typescript-eslint/member-ordering
  1571. Criteria.luxonDateConditions = {
  1572. '=': {
  1573. conditionName: function (dt, i18n) {
  1574. return dt.i18n('searchBuilder.conditions.date.equals', i18n.conditions.date.equals);
  1575. },
  1576. init: Criteria.initDate,
  1577. inputValue: Criteria.inputValueInput,
  1578. isInputValid: Criteria.isInputValidInput,
  1579. search: function (value, comparison, that) {
  1580. return luxon.DateTime.fromFormat(value, that.s.dateFormat).ts
  1581. === luxon.DateTime.fromFormat(comparison[0], that.s.dateFormat).ts;
  1582. }
  1583. },
  1584. // eslint-disable-next-line sort-keys
  1585. '!=': {
  1586. conditionName: function (dt, i18n) {
  1587. return dt.i18n('searchBuilder.conditions.date.not', i18n.conditions.date.not);
  1588. },
  1589. init: Criteria.initDate,
  1590. inputValue: Criteria.inputValueInput,
  1591. isInputValid: Criteria.isInputValidInput,
  1592. search: function (value, comparison, that) {
  1593. return luxon.DateTime.fromFormat(value, that.s.dateFormat).ts
  1594. !== luxon.DateTime.fromFormat(comparison[0], that.s.dateFormat).ts;
  1595. }
  1596. },
  1597. '<': {
  1598. conditionName: function (dt, i18n) {
  1599. return dt.i18n('searchBuilder.conditions.date.before', i18n.conditions.date.before);
  1600. },
  1601. init: Criteria.initDate,
  1602. inputValue: Criteria.inputValueInput,
  1603. isInputValid: Criteria.isInputValidInput,
  1604. search: function (value, comparison, that) {
  1605. return luxon.DateTime.fromFormat(value, that.s.dateFormat).ts
  1606. < luxon.DateTime.fromFormat(comparison[0], that.s.dateFormat).ts;
  1607. }
  1608. },
  1609. '>': {
  1610. conditionName: function (dt, i18n) {
  1611. return dt.i18n('searchBuilder.conditions.date.after', i18n.conditions.date.after);
  1612. },
  1613. init: Criteria.initDate,
  1614. inputValue: Criteria.inputValueInput,
  1615. isInputValid: Criteria.isInputValidInput,
  1616. search: function (value, comparison, that) {
  1617. return luxon.DateTime.fromFormat(value, that.s.dateFormat).ts
  1618. > luxon.DateTime.fromFormat(comparison[0], that.s.dateFormat).ts;
  1619. }
  1620. },
  1621. 'between': {
  1622. conditionName: function (dt, i18n) {
  1623. return dt.i18n('searchBuilder.conditions.date.between', i18n.conditions.date.between);
  1624. },
  1625. init: Criteria.init2Date,
  1626. inputValue: Criteria.inputValueInput,
  1627. isInputValid: Criteria.isInputValidInput,
  1628. search: function (value, comparison, that) {
  1629. var val = luxon.DateTime.fromFormat(value, that.s.dateFormat).ts;
  1630. var comp0 = luxon.DateTime.fromFormat(comparison[0], that.s.dateFormat).ts;
  1631. var comp1 = luxon.DateTime.fromFormat(comparison[1], that.s.dateFormat).ts;
  1632. if (comp0 < comp1) {
  1633. return comp0 <= val && val <= comp1;
  1634. }
  1635. else {
  1636. return comp1 <= val && val <= comp0;
  1637. }
  1638. }
  1639. },
  1640. // eslint-disable-next-line sort-keys
  1641. '!between': {
  1642. conditionName: function (dt, i18n) {
  1643. return dt.i18n('searchBuilder.conditions.date.notBetween', i18n.conditions.date.notBetween);
  1644. },
  1645. init: Criteria.init2Date,
  1646. inputValue: Criteria.inputValueInput,
  1647. isInputValid: Criteria.isInputValidInput,
  1648. search: function (value, comparison, that) {
  1649. var val = luxon.DateTime.fromFormat(value, that.s.dateFormat).ts;
  1650. var comp0 = luxon.DateTime.fromFormat(comparison[0], that.s.dateFormat).ts;
  1651. var comp1 = luxon.DateTime.fromFormat(comparison[1], that.s.dateFormat).ts;
  1652. if (comp0 < comp1) {
  1653. return !(+comp0 <= +val && +val <= +comp1);
  1654. }
  1655. else {
  1656. return !(+comp1 <= +val && +val <= +comp0);
  1657. }
  1658. }
  1659. },
  1660. 'null': {
  1661. conditionName: function (dt, i18n) {
  1662. return dt.i18n('searchBuilder.conditions.date.empty', i18n.conditions.date.empty);
  1663. },
  1664. init: Criteria.initNoValue,
  1665. inputValue: function () {
  1666. return;
  1667. },
  1668. isInputValid: function () {
  1669. return true;
  1670. },
  1671. search: function (value) {
  1672. return value === null || value === undefined || value.length === 0;
  1673. }
  1674. },
  1675. // eslint-disable-next-line sort-keys
  1676. '!null': {
  1677. conditionName: function (dt, i18n) {
  1678. return dt.i18n('searchBuilder.conditions.date.notEmpty', i18n.conditions.date.notEmpty);
  1679. },
  1680. init: Criteria.initNoValue,
  1681. inputValue: function () {
  1682. return;
  1683. },
  1684. isInputValid: function () {
  1685. return true;
  1686. },
  1687. search: function (value) {
  1688. return !(value === null || value === undefined || value.length === 0);
  1689. }
  1690. }
  1691. };
  1692. // The order of the conditions will make eslint sad :(
  1693. // Has to be in this order so that they are displayed correctly in select elements
  1694. // Also have to disable member ordering for this as the private methods used are not yet declared otherwise
  1695. // eslint-disable-next-line @typescript-eslint/member-ordering
  1696. Criteria.numConditions = {
  1697. '=': {
  1698. conditionName: function (dt, i18n) {
  1699. return dt.i18n('searchBuilder.conditions.number.equals', i18n.conditions.number.equals);
  1700. },
  1701. init: Criteria.initSelect,
  1702. inputValue: Criteria.inputValueSelect,
  1703. isInputValid: Criteria.isInputValidSelect,
  1704. search: function (value, comparison) {
  1705. return +value === +comparison[0];
  1706. }
  1707. },
  1708. // eslint-disable-next-line sort-keys
  1709. '!=': {
  1710. conditionName: function (dt, i18n) {
  1711. return dt.i18n('searchBuilder.conditions.number.not', i18n.conditions.number.not);
  1712. },
  1713. init: Criteria.initSelect,
  1714. inputValue: Criteria.inputValueSelect,
  1715. isInputValid: Criteria.isInputValidSelect,
  1716. search: function (value, comparison) {
  1717. return +value !== +comparison[0];
  1718. }
  1719. },
  1720. '<': {
  1721. conditionName: function (dt, i18n) {
  1722. return dt.i18n('searchBuilder.conditions.number.lt', i18n.conditions.number.lt);
  1723. },
  1724. init: Criteria.initInput,
  1725. inputValue: Criteria.inputValueInput,
  1726. isInputValid: Criteria.isInputValidInput,
  1727. search: function (value, comparison) {
  1728. return +value < +comparison[0];
  1729. }
  1730. },
  1731. '<=': {
  1732. conditionName: function (dt, i18n) {
  1733. return dt.i18n('searchBuilder.conditions.number.lte', i18n.conditions.number.lte);
  1734. },
  1735. init: Criteria.initInput,
  1736. inputValue: Criteria.inputValueInput,
  1737. isInputValid: Criteria.isInputValidInput,
  1738. search: function (value, comparison) {
  1739. return +value <= +comparison[0];
  1740. }
  1741. },
  1742. '>=': {
  1743. conditionName: function (dt, i18n) {
  1744. return dt.i18n('searchBuilder.conditions.number.gte', i18n.conditions.number.gte);
  1745. },
  1746. init: Criteria.initInput,
  1747. inputValue: Criteria.inputValueInput,
  1748. isInputValid: Criteria.isInputValidInput,
  1749. search: function (value, comparison) {
  1750. return +value >= +comparison[0];
  1751. }
  1752. },
  1753. // eslint-disable-next-line sort-keys
  1754. '>': {
  1755. conditionName: function (dt, i18n) {
  1756. return dt.i18n('searchBuilder.conditions.number.gt', i18n.conditions.number.gt);
  1757. },
  1758. init: Criteria.initInput,
  1759. inputValue: Criteria.inputValueInput,
  1760. isInputValid: Criteria.isInputValidInput,
  1761. search: function (value, comparison) {
  1762. return +value > +comparison[0];
  1763. }
  1764. },
  1765. 'between': {
  1766. conditionName: function (dt, i18n) {
  1767. return dt.i18n('searchBuilder.conditions.number.between', i18n.conditions.number.between);
  1768. },
  1769. init: Criteria.init2Input,
  1770. inputValue: Criteria.inputValueInput,
  1771. isInputValid: Criteria.isInputValidInput,
  1772. search: function (value, comparison) {
  1773. if (+comparison[0] < +comparison[1]) {
  1774. return +comparison[0] <= +value && +value <= +comparison[1];
  1775. }
  1776. else {
  1777. return +comparison[1] <= +value && +value <= +comparison[0];
  1778. }
  1779. }
  1780. },
  1781. // eslint-disable-next-line sort-keys
  1782. '!between': {
  1783. conditionName: function (dt, i18n) {
  1784. return dt.i18n('searchBuilder.conditions.number.notBetween', i18n.conditions.number.notBetween);
  1785. },
  1786. init: Criteria.init2Input,
  1787. inputValue: Criteria.inputValueInput,
  1788. isInputValid: Criteria.isInputValidInput,
  1789. search: function (value, comparison) {
  1790. if (+comparison[0] < +comparison[1]) {
  1791. return !(+comparison[0] <= +value && +value <= +comparison[1]);
  1792. }
  1793. else {
  1794. return !(+comparison[1] <= +value && +value <= +comparison[0]);
  1795. }
  1796. }
  1797. },
  1798. 'null': {
  1799. conditionName: function (dt, i18n) {
  1800. return dt.i18n('searchBuilder.conditions.number.empty', i18n.conditions.number.empty);
  1801. },
  1802. init: Criteria.initNoValue,
  1803. inputValue: function () {
  1804. return;
  1805. },
  1806. isInputValid: function () {
  1807. return true;
  1808. },
  1809. search: function (value) {
  1810. return value === null || value === undefined || value.length === 0;
  1811. }
  1812. },
  1813. // eslint-disable-next-line sort-keys
  1814. '!null': {
  1815. conditionName: function (dt, i18n) {
  1816. return dt.i18n('searchBuilder.conditions.number.notEmpty', i18n.conditions.number.notEmpty);
  1817. },
  1818. init: Criteria.initNoValue,
  1819. inputValue: function () {
  1820. return;
  1821. },
  1822. isInputValid: function () {
  1823. return true;
  1824. },
  1825. search: function (value) {
  1826. return !(value === null || value === undefined || value.length === 0);
  1827. }
  1828. }
  1829. };
  1830. // The order of the conditions will make eslint sad :(
  1831. // Has to be in this order so that they are displayed correctly in select elements
  1832. // Also have to disable member ordering for this as the private methods used are not yet declared otherwise
  1833. // eslint-disable-next-line @typescript-eslint/member-ordering
  1834. Criteria.numFmtConditions = {
  1835. '=': {
  1836. conditionName: function (dt, i18n) {
  1837. return dt.i18n('searchBuilder.conditions.number.equals', i18n.conditions.number.equals);
  1838. },
  1839. init: Criteria.initSelect,
  1840. inputValue: Criteria.inputValueSelect,
  1841. isInputValid: Criteria.isInputValidSelect,
  1842. search: function (value, comparison) {
  1843. var val = value.indexOf('-') === 0 ?
  1844. '-' + value.replace(/[^0-9.]/g, '') :
  1845. value.replace(/[^0-9.]/g, '');
  1846. var comp = comparison[0].indexOf('-') === 0 ?
  1847. '-' + comparison[0].replace(/[^0-9.]/g, '') :
  1848. comparison[0].replace(/[^0-9.]/g, '');
  1849. return +val === +comp;
  1850. }
  1851. },
  1852. // eslint-disable-next-line sort-keys
  1853. '!=': {
  1854. conditionName: function (dt, i18n) {
  1855. return dt.i18n('searchBuilder.conditions.number.not', i18n.conditions.number.not);
  1856. },
  1857. init: Criteria.initSelect,
  1858. inputValue: Criteria.inputValueSelect,
  1859. isInputValid: Criteria.isInputValidSelect,
  1860. search: function (value, comparison) {
  1861. var val = value.indexOf('-') === 0 ?
  1862. '-' + value.replace(/[^0-9.]/g, '') :
  1863. value.replace(/[^0-9.]/g, '');
  1864. var comp = comparison[0].indexOf('-') === 0 ?
  1865. '-' + comparison[0].replace(/[^0-9.]/g, '') :
  1866. comparison[0].replace(/[^0-9.]/g, '');
  1867. return +val !== +comp;
  1868. }
  1869. },
  1870. '<': {
  1871. conditionName: function (dt, i18n) {
  1872. return dt.i18n('searchBuilder.conditions.number.lt', i18n.conditions.number.lt);
  1873. },
  1874. init: Criteria.initInput,
  1875. inputValue: Criteria.inputValueInput,
  1876. isInputValid: Criteria.isInputValidInput,
  1877. search: function (value, comparison) {
  1878. var val = value.indexOf('-') === 0 ?
  1879. '-' + value.replace(/[^0-9.]/g, '') :
  1880. value.replace(/[^0-9.]/g, '');
  1881. var comp = comparison[0].indexOf('-') === 0 ?
  1882. '-' + comparison[0].replace(/[^0-9.]/g, '') :
  1883. comparison[0].replace(/[^0-9.]/g, '');
  1884. return +val < +comp;
  1885. }
  1886. },
  1887. '<=': {
  1888. conditionName: function (dt, i18n) {
  1889. return dt.i18n('searchBuilder.conditions.number.lte', i18n.conditions.number.lte);
  1890. },
  1891. init: Criteria.initInput,
  1892. inputValue: Criteria.inputValueInput,
  1893. isInputValid: Criteria.isInputValidInput,
  1894. search: function (value, comparison) {
  1895. var val = value.indexOf('-') === 0 ?
  1896. '-' + value.replace(/[^0-9.]/g, '') :
  1897. value.replace(/[^0-9.]/g, '');
  1898. var comp = comparison[0].indexOf('-') === 0 ?
  1899. '-' + comparison[0].replace(/[^0-9.]/g, '') :
  1900. comparison[0].replace(/[^0-9.]/g, '');
  1901. return +val <= +comp;
  1902. }
  1903. },
  1904. '>=': {
  1905. conditionName: function (dt, i18n) {
  1906. return dt.i18n('searchBuilder.conditions.number.gte', i18n.conditions.number.gte);
  1907. },
  1908. init: Criteria.initInput,
  1909. inputValue: Criteria.inputValueInput,
  1910. isInputValid: Criteria.isInputValidInput,
  1911. search: function (value, comparison) {
  1912. var val = value.indexOf('-') === 0 ?
  1913. '-' + value.replace(/[^0-9.]/g, '') :
  1914. value.replace(/[^0-9.]/g, '');
  1915. var comp = comparison[0].indexOf('-') === 0 ?
  1916. '-' + comparison[0].replace(/[^0-9.]/g, '') :
  1917. comparison[0].replace(/[^0-9.]/g, '');
  1918. return +val >= +comp;
  1919. }
  1920. },
  1921. // eslint-disable-next-line sort-keys
  1922. '>': {
  1923. conditionName: function (dt, i18n) {
  1924. return dt.i18n('searchBuilder.conditions.number.gt', i18n.conditions.number.gt);
  1925. },
  1926. init: Criteria.initInput,
  1927. inputValue: Criteria.inputValueInput,
  1928. isInputValid: Criteria.isInputValidInput,
  1929. search: function (value, comparison) {
  1930. var val = value.indexOf('-') === 0 ?
  1931. '-' + value.replace(/[^0-9.]/g, '') :
  1932. value.replace(/[^0-9.]/g, '');
  1933. var comp = comparison[0].indexOf('-') === 0 ?
  1934. '-' + comparison[0].replace(/[^0-9.]/g, '') :
  1935. comparison[0].replace(/[^0-9.]/g, '');
  1936. return +val > +comp;
  1937. }
  1938. },
  1939. 'between': {
  1940. conditionName: function (dt, i18n) {
  1941. return dt.i18n('searchBuilder.conditions.number.between', i18n.conditions.number.between);
  1942. },
  1943. init: Criteria.init2Input,
  1944. inputValue: Criteria.inputValueInput,
  1945. isInputValid: Criteria.isInputValidInput,
  1946. search: function (value, comparison) {
  1947. var val = value.indexOf('-') === 0 ?
  1948. '-' + value.replace(/[^0-9.]/g, '') :
  1949. value.replace(/[^0-9.]/g, '');
  1950. var comp0 = comparison[0].indexOf('-') === 0 ?
  1951. '-' + comparison[0].replace(/[^0-9.]/g, '') :
  1952. comparison[0].replace(/[^0-9.]/g, '');
  1953. var comp1 = comparison[1].indexOf('-') === 0 ?
  1954. '-' + comparison[1].replace(/[^0-9.]/g, '') :
  1955. comparison[1].replace(/[^0-9.]/g, '');
  1956. if (+comp0 < +comp1) {
  1957. return +comp0 <= +val && +val <= +comp1;
  1958. }
  1959. else {
  1960. return +comp1 <= +val && +val <= +comp0;
  1961. }
  1962. }
  1963. },
  1964. // eslint-disable-next-line sort-keys
  1965. '!between': {
  1966. conditionName: function (dt, i18n) {
  1967. return dt.i18n('searchBuilder.conditions.number.notBetween', i18n.conditions.number.notBetween);
  1968. },
  1969. init: Criteria.init2Input,
  1970. inputValue: Criteria.inputValueInput,
  1971. isInputValid: Criteria.isInputValidInput,
  1972. search: function (value, comparison) {
  1973. var val = value.indexOf('-') === 0 ?
  1974. '-' + value.replace(/[^0-9.]/g, '') :
  1975. value.replace(/[^0-9.]/g, '');
  1976. var comp0 = comparison[0].indexOf('-') === 0 ?
  1977. '-' + comparison[0].replace(/[^0-9.]/g, '') :
  1978. comparison[0].replace(/[^0-9.]/g, '');
  1979. var comp1 = comparison[1].indexOf('-') === 0 ?
  1980. '-' + comparison[1].replace(/[^0-9.]/g, '') :
  1981. comparison[1].replace(/[^0-9.]/g, '');
  1982. if (+comp0 < +comp1) {
  1983. return !(+comp0 <= +val && +val <= +comp1);
  1984. }
  1985. else {
  1986. return !(+comp1 <= +val && +val <= +comp0);
  1987. }
  1988. }
  1989. },
  1990. 'null': {
  1991. conditionName: function (dt, i18n) {
  1992. return dt.i18n('searchBuilder.conditions.number.empty', i18n.conditions.number.empty);
  1993. },
  1994. init: Criteria.initNoValue,
  1995. inputValue: function () {
  1996. return;
  1997. },
  1998. isInputValid: function () {
  1999. return true;
  2000. },
  2001. search: function (value) {
  2002. return value === null || value === undefined || value.length === 0;
  2003. }
  2004. },
  2005. // eslint-disable-next-line sort-keys
  2006. '!null': {
  2007. conditionName: function (dt, i18n) {
  2008. return dt.i18n('searchBuilder.conditions.number.notEmpty', i18n.conditions.number.notEmpty);
  2009. },
  2010. init: Criteria.initNoValue,
  2011. inputValue: function () {
  2012. return;
  2013. },
  2014. isInputValid: function () {
  2015. return true;
  2016. },
  2017. search: function (value) {
  2018. return !(value === null || value === undefined || value.length === 0);
  2019. }
  2020. }
  2021. };
  2022. // The order of the conditions will make eslint sad :(
  2023. // Has to be in this order so that they are displayed correctly in select elements
  2024. // Also have to disable member ordering for this as the private methods used are not yet declared otherwise
  2025. // eslint-disable-next-line @typescript-eslint/member-ordering
  2026. Criteria.stringConditions = {
  2027. '=': {
  2028. conditionName: function (dt, i18n) {
  2029. return dt.i18n('searchBuilder.conditions.string.equals', i18n.conditions.string.equals);
  2030. },
  2031. init: Criteria.initSelect,
  2032. inputValue: Criteria.inputValueSelect,
  2033. isInputValid: Criteria.isInputValidSelect,
  2034. search: function (value, comparison) {
  2035. return value === comparison[0];
  2036. }
  2037. },
  2038. // eslint-disable-next-line sort-keys
  2039. '!=': {
  2040. conditionName: function (dt, i18n) {
  2041. return dt.i18n('searchBuilder.conditions.string.not', i18n.conditions.string.not);
  2042. },
  2043. init: Criteria.initSelect,
  2044. inputValue: Criteria.inputValueSelect,
  2045. isInputValid: Criteria.isInputValidInput,
  2046. search: function (value, comparison) {
  2047. return value !== comparison[0];
  2048. }
  2049. },
  2050. 'starts': {
  2051. conditionName: function (dt, i18n) {
  2052. return dt.i18n('searchBuilder.conditions.string.startsWith', i18n.conditions.string.startsWith);
  2053. },
  2054. init: Criteria.initInput,
  2055. inputValue: Criteria.inputValueInput,
  2056. isInputValid: Criteria.isInputValidInput,
  2057. search: function (value, comparison) {
  2058. return value.toLowerCase().indexOf(comparison[0].toLowerCase()) === 0;
  2059. }
  2060. },
  2061. // eslint-disable-next-line sort-keys
  2062. 'contains': {
  2063. conditionName: function (dt, i18n) {
  2064. return dt.i18n('searchBuilder.conditions.string.contains', i18n.conditions.string.contains);
  2065. },
  2066. init: Criteria.initInput,
  2067. inputValue: Criteria.inputValueInput,
  2068. isInputValid: Criteria.isInputValidInput,
  2069. search: function (value, comparison) {
  2070. return value.toLowerCase().includes(comparison[0].toLowerCase());
  2071. }
  2072. },
  2073. 'ends': {
  2074. conditionName: function (dt, i18n) {
  2075. return dt.i18n('searchBuilder.conditions.string.endsWith', i18n.conditions.string.endsWith);
  2076. },
  2077. init: Criteria.initInput,
  2078. inputValue: Criteria.inputValueInput,
  2079. isInputValid: Criteria.isInputValidInput,
  2080. search: function (value, comparison) {
  2081. return value.toLowerCase().endsWith(comparison[0].toLowerCase());
  2082. }
  2083. },
  2084. 'null': {
  2085. conditionName: function (dt, i18n) {
  2086. return dt.i18n('searchBuilder.conditions.string.empty', i18n.conditions.string.empty);
  2087. },
  2088. init: Criteria.initNoValue,
  2089. inputValue: function () {
  2090. return;
  2091. },
  2092. isInputValid: function () {
  2093. return true;
  2094. },
  2095. search: function (value) {
  2096. return value === null || value === undefined || value.length === 0;
  2097. }
  2098. },
  2099. // eslint-disable-next-line sort-keys
  2100. '!null': {
  2101. conditionName: function (dt, i18n) {
  2102. return dt.i18n('searchBuilder.conditions.string.notEmpty', i18n.conditions.string.notEmpty);
  2103. },
  2104. init: Criteria.initNoValue,
  2105. inputValue: function () {
  2106. return;
  2107. },
  2108. isInputValid: function () {
  2109. return true;
  2110. },
  2111. search: function (value) {
  2112. return !(value === null || value === undefined || value.length === 0);
  2113. }
  2114. }
  2115. };
  2116. // The order of the conditions will make eslint sad :(
  2117. // Also have to disable member ordering for this as the private methods used are not yet declared otherwise
  2118. // eslint-disable-next-line @typescript-eslint/member-ordering
  2119. Criteria.arrayConditions = {
  2120. 'contains': {
  2121. conditionName: function (dt, i18n) {
  2122. return dt.i18n('searchBuilder.conditions.array.contains', i18n.conditions.array.contains);
  2123. },
  2124. init: Criteria.initSelectArray,
  2125. inputValue: Criteria.inputValueSelect,
  2126. isInputValid: Criteria.isInputValidSelect,
  2127. search: function (value, comparison) {
  2128. return value.includes(comparison[0]);
  2129. }
  2130. },
  2131. 'without': {
  2132. conditionName: function (dt, i18n) {
  2133. return dt.i18n('searchBuilder.conditions.array.without', i18n.conditions.array.without);
  2134. },
  2135. init: Criteria.initSelectArray,
  2136. inputValue: Criteria.inputValueSelect,
  2137. isInputValid: Criteria.isInputValidSelect,
  2138. search: function (value, comparison) {
  2139. return value.indexOf(comparison[0]) === -1;
  2140. }
  2141. },
  2142. // eslint-disable-next-line sort-keys
  2143. '=': {
  2144. conditionName: function (dt, i18n) {
  2145. return dt.i18n('searchBuilder.conditions.array.equals', i18n.conditions.array.equals);
  2146. },
  2147. init: Criteria.initSelect,
  2148. inputValue: Criteria.inputValueSelect,
  2149. isInputValid: Criteria.isInputValidSelect,
  2150. search: function (value, comparison) {
  2151. if (value.length === comparison[0].length) {
  2152. for (var i = 0; i < value.length; i++) {
  2153. if (value[i] !== comparison[0][i]) {
  2154. return false;
  2155. }
  2156. }
  2157. return true;
  2158. }
  2159. return false;
  2160. }
  2161. },
  2162. // eslint-disable-next-line sort-keys
  2163. '!=': {
  2164. conditionName: function (dt, i18n) {
  2165. return dt.i18n('searchBuilder.conditions.array.not', i18n.conditions.array.not);
  2166. },
  2167. init: Criteria.initSelect,
  2168. inputValue: Criteria.inputValueSelect,
  2169. isInputValid: Criteria.isInputValidSelect,
  2170. search: function (value, comparison) {
  2171. if (value.length === comparison[0].length) {
  2172. for (var i = 0; i < value.length; i++) {
  2173. if (value[i] !== comparison[0][i]) {
  2174. return true;
  2175. }
  2176. }
  2177. return false;
  2178. }
  2179. return true;
  2180. }
  2181. },
  2182. 'null': {
  2183. conditionName: function (dt, i18n) {
  2184. return dt.i18n('searchBuilder.conditions.array.empty', i18n.conditions.array.empty);
  2185. },
  2186. init: Criteria.initNoValue,
  2187. inputValue: function () {
  2188. return;
  2189. },
  2190. isInputValid: function () {
  2191. return true;
  2192. },
  2193. search: function (value) {
  2194. return value === null || value === undefined || value.length === 0;
  2195. }
  2196. },
  2197. // eslint-disable-next-line sort-keys
  2198. '!null': {
  2199. conditionName: function (dt, i18n) {
  2200. return dt.i18n('searchBuilder.conditions.array.notEmpty', i18n.conditions.array.notEmpty);
  2201. },
  2202. init: Criteria.initNoValue,
  2203. inputValue: function () {
  2204. return;
  2205. },
  2206. isInputValid: function () {
  2207. return true;
  2208. },
  2209. search: function (value) {
  2210. return value !== null && value !== undefined && value.length !== 0;
  2211. }
  2212. }
  2213. };
  2214. // eslint will be sad because we have to disable member ordering for this as the
  2215. // private static properties used are not yet declared otherwise
  2216. // eslint-disable-next-line @typescript-eslint/member-ordering
  2217. Criteria.defaults = {
  2218. columns: true,
  2219. conditions: {
  2220. 'array': Criteria.arrayConditions,
  2221. 'date': Criteria.dateConditions,
  2222. 'html': Criteria.stringConditions,
  2223. 'html-num': Criteria.numConditions,
  2224. 'html-num-fmt': Criteria.numFmtConditions,
  2225. 'luxon': Criteria.luxonDateConditions,
  2226. 'moment': Criteria.momentDateConditions,
  2227. 'num': Criteria.numConditions,
  2228. 'num-fmt': Criteria.numFmtConditions,
  2229. 'string': Criteria.stringConditions
  2230. },
  2231. depthLimit: false,
  2232. enterSearch: false,
  2233. filterChanged: undefined,
  2234. greyscale: false,
  2235. i18n: {
  2236. add: 'Add Condition',
  2237. button: {
  2238. 0: 'Search Builder',
  2239. _: 'Search Builder (%d)'
  2240. },
  2241. clearAll: 'Clear All',
  2242. condition: 'Condition',
  2243. data: 'Data',
  2244. deleteTitle: 'Delete filtering rule',
  2245. leftTitle: 'Outdent criteria',
  2246. logicAnd: 'And',
  2247. logicOr: 'Or',
  2248. rightTitle: 'Indent criteria',
  2249. title: {
  2250. 0: 'Custom Search Builder',
  2251. _: 'Custom Search Builder (%d)'
  2252. },
  2253. value: 'Value',
  2254. valueJoiner: 'and'
  2255. },
  2256. logic: 'AND',
  2257. orthogonal: {
  2258. display: 'display',
  2259. search: 'filter'
  2260. },
  2261. preDefined: false
  2262. };
  2263. return Criteria;
  2264. }());
  2265. var $$1;
  2266. var dataTable$1;
  2267. /**
  2268. * Sets the value of jQuery for use in the file
  2269. *
  2270. * @param jq the instance of jQuery to be set
  2271. */
  2272. function setJQuery$1(jq) {
  2273. $$1 = jq;
  2274. dataTable$1 = jq.fn.dataTable;
  2275. }
  2276. /**
  2277. * The Group class is used within SearchBuilder to represent a group of criteria
  2278. */
  2279. var Group = /** @class */ (function () {
  2280. function Group(table, opts, topGroup, index, isChild, depth) {
  2281. if (index === void 0) { index = 0; }
  2282. if (isChild === void 0) { isChild = false; }
  2283. if (depth === void 0) { depth = 1; }
  2284. // Check that the required version of DataTables is included
  2285. if (!dataTable$1 || !dataTable$1.versionCheck || !dataTable$1.versionCheck('1.10.0')) {
  2286. throw new Error('SearchBuilder requires DataTables 1.10 or newer');
  2287. }
  2288. this.classes = $$1.extend(true, {}, Group.classes);
  2289. // Get options from user
  2290. this.c = $$1.extend(true, {}, Group.defaults, opts);
  2291. this.s = {
  2292. criteria: [],
  2293. depth: depth,
  2294. dt: table,
  2295. index: index,
  2296. isChild: isChild,
  2297. logic: undefined,
  2298. opts: opts,
  2299. toDrop: undefined,
  2300. topGroup: topGroup
  2301. };
  2302. this.dom = {
  2303. add: $$1('<button/>')
  2304. .addClass(this.classes.add)
  2305. .addClass(this.classes.button)
  2306. .attr('type', 'button'),
  2307. clear: $$1('<button>&times</button>')
  2308. .addClass(this.classes.button)
  2309. .addClass(this.classes.clearGroup)
  2310. .attr('type', 'button'),
  2311. container: $$1('<div/>')
  2312. .addClass(this.classes.group),
  2313. logic: $$1('<button><div/></button>')
  2314. .addClass(this.classes.logic)
  2315. .addClass(this.classes.button)
  2316. .attr('type', 'button'),
  2317. logicContainer: $$1('<div/>')
  2318. .addClass(this.classes.logicContainer)
  2319. };
  2320. // A reference to the top level group is maintained throughout any subgroups and criteria that may be created
  2321. if (this.s.topGroup === undefined) {
  2322. this.s.topGroup = this.dom.container;
  2323. }
  2324. this._setup();
  2325. return this;
  2326. }
  2327. /**
  2328. * Destroys the groups buttons, clears the internal criteria and removes it from the dom
  2329. */
  2330. Group.prototype.destroy = function () {
  2331. // Turn off listeners
  2332. this.dom.add.off('.dtsb');
  2333. this.dom.logic.off('.dtsb');
  2334. // Trigger event for groups at a higher level to pick up on
  2335. this.dom.container
  2336. .trigger('dtsb-destroy')
  2337. .remove();
  2338. this.s.criteria = [];
  2339. };
  2340. /**
  2341. * Gets the details required to rebuild the group
  2342. */
  2343. // Eslint upset at empty object but needs to be done
  2344. // eslint-disable-next-line @typescript-eslint/ban-types
  2345. Group.prototype.getDetails = function () {
  2346. if (this.s.criteria.length === 0) {
  2347. return {};
  2348. }
  2349. var details = {
  2350. criteria: [],
  2351. logic: this.s.logic
  2352. };
  2353. // NOTE here crit could be either a subgroup or a criteria
  2354. for (var _i = 0, _a = this.s.criteria; _i < _a.length; _i++) {
  2355. var crit = _a[_i];
  2356. details.criteria.push(crit.criteria.getDetails());
  2357. }
  2358. return details;
  2359. };
  2360. /**
  2361. * Getter for the node for the container of the group
  2362. *
  2363. * @returns Node for the container of the group
  2364. */
  2365. Group.prototype.getNode = function () {
  2366. return this.dom.container;
  2367. };
  2368. /**
  2369. * Rebuilds the group based upon the details passed in
  2370. *
  2371. * @param loadedDetails the details required to rebuild the group
  2372. */
  2373. Group.prototype.rebuild = function (loadedDetails) {
  2374. // If no criteria are stored then just return
  2375. if (loadedDetails.criteria === undefined ||
  2376. loadedDetails.criteria === null ||
  2377. Array.isArray(loadedDetails.criteria) && loadedDetails.criteria.length === 0) {
  2378. return;
  2379. }
  2380. this.s.logic = loadedDetails.logic;
  2381. this.dom.logic.children().first().text(this.s.logic === 'OR'
  2382. ? this.s.dt.i18n('searchBuilder.logicOr', this.c.i18n.logicOr)
  2383. : this.s.dt.i18n('searchBuilder.logicAnd', this.c.i18n.logicAnd));
  2384. // Add all of the criteria, be it a sub group or a criteria
  2385. if (Array.isArray(loadedDetails.criteria)) {
  2386. for (var _i = 0, _a = loadedDetails.criteria; _i < _a.length; _i++) {
  2387. var crit = _a[_i];
  2388. if (crit.logic !== undefined) {
  2389. this._addPrevGroup(crit);
  2390. }
  2391. else if (crit.logic === undefined) {
  2392. this._addPrevCriteria(crit);
  2393. }
  2394. }
  2395. }
  2396. // For all of the criteria children, update the arrows incase they require changing and set the listeners
  2397. for (var _b = 0, _c = this.s.criteria; _b < _c.length; _b++) {
  2398. var crit = _c[_b];
  2399. if (crit.criteria instanceof Criteria) {
  2400. crit.criteria.updateArrows(this.s.criteria.length > 1, false);
  2401. this._setCriteriaListeners(crit.criteria);
  2402. }
  2403. }
  2404. };
  2405. /**
  2406. * Redraws the Contents of the searchBuilder Groups and Criteria
  2407. */
  2408. Group.prototype.redrawContents = function () {
  2409. // Clear the container out and add the basic elements
  2410. this.dom.container.children().detach();
  2411. this.dom.container
  2412. .append(this.dom.logicContainer)
  2413. .append(this.dom.add);
  2414. // Sort the criteria by index so that they appear in the correct order
  2415. this.s.criteria.sort(function (a, b) {
  2416. if (a.criteria.s.index < b.criteria.s.index) {
  2417. return -1;
  2418. }
  2419. else if (a.criteria.s.index > b.criteria.s.index) {
  2420. return 1;
  2421. }
  2422. return 0;
  2423. });
  2424. this.setListeners();
  2425. for (var i = 0; i < this.s.criteria.length; i++) {
  2426. var crit = this.s.criteria[i].criteria;
  2427. if (crit instanceof Criteria) {
  2428. // Reset the index to the new value
  2429. this.s.criteria[i].index = i;
  2430. this.s.criteria[i].criteria.s.index = i;
  2431. // Add to the group
  2432. this.s.criteria[i].criteria.dom.container.insertBefore(this.dom.add);
  2433. // Set listeners for various points
  2434. this._setCriteriaListeners(crit);
  2435. this.s.criteria[i].criteria.rebuild(this.s.criteria[i].criteria.getDetails());
  2436. }
  2437. else if (crit instanceof Group && crit.s.criteria.length > 0) {
  2438. // Reset the index to the new value
  2439. this.s.criteria[i].index = i;
  2440. this.s.criteria[i].criteria.s.index = i;
  2441. // Add the sub group to the group
  2442. this.s.criteria[i].criteria.dom.container.insertBefore(this.dom.add);
  2443. // Redraw the contents of the group
  2444. crit.redrawContents();
  2445. this._setGroupListeners(crit);
  2446. }
  2447. else {
  2448. // The group is empty so remove it
  2449. this.s.criteria.splice(i, 1);
  2450. i--;
  2451. }
  2452. }
  2453. this.setupLogic();
  2454. };
  2455. /**
  2456. * Resizes the logic button only rather than the entire dom.
  2457. */
  2458. Group.prototype.redrawLogic = function () {
  2459. for (var _i = 0, _a = this.s.criteria; _i < _a.length; _i++) {
  2460. var crit = _a[_i];
  2461. if (crit instanceof Group) {
  2462. crit.redrawLogic();
  2463. }
  2464. }
  2465. this.setupLogic();
  2466. };
  2467. /**
  2468. * Search method, checking the row data against the criteria in the group
  2469. *
  2470. * @param rowData The row data to be compared
  2471. * @returns boolean The result of the search
  2472. */
  2473. Group.prototype.search = function (rowData, rowIdx) {
  2474. if (this.s.logic === 'AND') {
  2475. return this._andSearch(rowData, rowIdx);
  2476. }
  2477. else if (this.s.logic === 'OR') {
  2478. return this._orSearch(rowData, rowIdx);
  2479. }
  2480. return true;
  2481. };
  2482. /**
  2483. * Locates the groups logic button to the correct location on the page
  2484. */
  2485. Group.prototype.setupLogic = function () {
  2486. // Remove logic button
  2487. this.dom.logicContainer.remove();
  2488. this.dom.clear.remove();
  2489. // If there are no criteria in the group then keep the logic removed and return
  2490. if (this.s.criteria.length < 1) {
  2491. if (!this.s.isChild) {
  2492. this.dom.container.trigger('dtsb-destroy');
  2493. // Set criteria left margin
  2494. this.dom.container.css('margin-left', 0);
  2495. }
  2496. return;
  2497. }
  2498. // Set width, take 2 for the border
  2499. var height = this.dom.container.height() - 1;
  2500. this.dom.clear.height('0px');
  2501. this.dom.logicContainer.append(this.dom.clear).width(height);
  2502. // Prepend logic button
  2503. this.dom.container.prepend(this.dom.logicContainer);
  2504. this._setLogicListener();
  2505. // Set criteria left margin
  2506. this.dom.container.css('margin-left', this.dom.logicContainer.outerHeight(true));
  2507. var logicOffset = this.dom.logicContainer.offset();
  2508. // Set horizontal alignment
  2509. var currentLeft = logicOffset.left;
  2510. var groupLeft = this.dom.container.offset().left;
  2511. var shuffleLeft = currentLeft - groupLeft;
  2512. var newPos = currentLeft - shuffleLeft - this.dom.logicContainer.outerHeight(true);
  2513. this.dom.logicContainer.offset({ left: newPos });
  2514. // Set vertical alignment
  2515. var firstCrit = this.dom.logicContainer.next();
  2516. var currentTop = logicOffset.top;
  2517. var firstTop = $$1(firstCrit).offset().top;
  2518. var shuffleTop = currentTop - firstTop;
  2519. var newTop = currentTop - shuffleTop;
  2520. this.dom.logicContainer.offset({ top: newTop });
  2521. this.dom.clear.outerHeight(this.dom.logicContainer.height());
  2522. this._setClearListener();
  2523. };
  2524. /**
  2525. * Sets listeners on the groups elements
  2526. */
  2527. Group.prototype.setListeners = function () {
  2528. var _this = this;
  2529. this.dom.add.unbind('click');
  2530. this.dom.add.on('click', function () {
  2531. // If this is the parent group then the logic button has not been added yet
  2532. if (!_this.s.isChild) {
  2533. _this.dom.container.prepend(_this.dom.logicContainer);
  2534. }
  2535. _this.addCriteria();
  2536. _this.dom.container.trigger('dtsb-add');
  2537. _this.s.dt.state.save();
  2538. return false;
  2539. });
  2540. for (var _i = 0, _a = this.s.criteria; _i < _a.length; _i++) {
  2541. var crit = _a[_i];
  2542. crit.criteria.setListeners();
  2543. }
  2544. this._setClearListener();
  2545. this._setLogicListener();
  2546. };
  2547. /**
  2548. * Adds a criteria to the group
  2549. *
  2550. * @param crit Instance of Criteria to be added to the group
  2551. */
  2552. Group.prototype.addCriteria = function (crit, redraw) {
  2553. if (crit === void 0) { crit = null; }
  2554. if (redraw === void 0) { redraw = true; }
  2555. var index = crit === null ? this.s.criteria.length : crit.s.index;
  2556. var criteria = new Criteria(this.s.dt, this.s.opts, this.s.topGroup, index, this.s.depth);
  2557. // If a Criteria has been passed in then set the values to continue that
  2558. if (crit !== null) {
  2559. criteria.c = crit.c;
  2560. criteria.s = crit.s;
  2561. criteria.s.depth = this.s.depth;
  2562. criteria.classes = crit.classes;
  2563. }
  2564. criteria.populate();
  2565. var inserted = false;
  2566. for (var i = 0; i < this.s.criteria.length; i++) {
  2567. if (i === 0 && this.s.criteria[i].criteria.s.index > criteria.s.index) {
  2568. // Add the node for the criteria at the start of the group
  2569. criteria.getNode().insertBefore(this.s.criteria[i].criteria.dom.container);
  2570. inserted = true;
  2571. }
  2572. else if (i < this.s.criteria.length - 1 &&
  2573. this.s.criteria[i].criteria.s.index < criteria.s.index &&
  2574. this.s.criteria[i + 1].criteria.s.index > criteria.s.index) {
  2575. // Add the node for the criteria in the correct location
  2576. criteria.getNode().insertAfter(this.s.criteria[i].criteria.dom.container);
  2577. inserted = true;
  2578. }
  2579. }
  2580. if (!inserted) {
  2581. criteria.getNode().insertBefore(this.dom.add);
  2582. }
  2583. // Add the details for this criteria to the array
  2584. this.s.criteria.push({
  2585. criteria: criteria,
  2586. index: index
  2587. });
  2588. this.s.criteria = this.s.criteria.sort(function (a, b) { return a.criteria.s.index - b.criteria.s.index; });
  2589. for (var _i = 0, _a = this.s.criteria; _i < _a.length; _i++) {
  2590. var opt = _a[_i];
  2591. if (opt.criteria instanceof Criteria) {
  2592. opt.criteria.updateArrows(this.s.criteria.length > 1, redraw);
  2593. }
  2594. }
  2595. this._setCriteriaListeners(criteria);
  2596. criteria.setListeners();
  2597. this.setupLogic();
  2598. };
  2599. /**
  2600. * Checks the group to see if it has any filled criteria
  2601. */
  2602. Group.prototype.checkFilled = function () {
  2603. for (var _i = 0, _a = this.s.criteria; _i < _a.length; _i++) {
  2604. var crit = _a[_i];
  2605. if (crit.criteria instanceof Criteria && crit.criteria.s.filled ||
  2606. crit.criteria instanceof Group && crit.criteria.checkFilled()) {
  2607. return true;
  2608. }
  2609. }
  2610. return false;
  2611. };
  2612. /**
  2613. * Gets the count for the number of criteria in this group and any sub groups
  2614. */
  2615. Group.prototype.count = function () {
  2616. var count = 0;
  2617. for (var _i = 0, _a = this.s.criteria; _i < _a.length; _i++) {
  2618. var crit = _a[_i];
  2619. if (crit.criteria instanceof Group) {
  2620. count += crit.criteria.count();
  2621. }
  2622. else {
  2623. count++;
  2624. }
  2625. }
  2626. return count;
  2627. };
  2628. /**
  2629. * Rebuilds a sub group that previously existed
  2630. *
  2631. * @param loadedGroup The details of a group within this group
  2632. */
  2633. Group.prototype._addPrevGroup = function (loadedGroup) {
  2634. var idx = this.s.criteria.length;
  2635. var group = new Group(this.s.dt, this.c, this.s.topGroup, idx, true, this.s.depth + 1);
  2636. // Add the new group to the criteria array
  2637. this.s.criteria.push({
  2638. criteria: group,
  2639. index: idx,
  2640. logic: group.s.logic
  2641. });
  2642. // Rebuild it with the previous conditions for that group
  2643. group.rebuild(loadedGroup);
  2644. this.s.criteria[idx].criteria = group;
  2645. this.s.topGroup.trigger('dtsb-redrawContents');
  2646. this._setGroupListeners(group);
  2647. };
  2648. /**
  2649. * Rebuilds a criteria of this group that previously existed
  2650. *
  2651. * @param loadedCriteria The details of a criteria within the group
  2652. */
  2653. Group.prototype._addPrevCriteria = function (loadedCriteria) {
  2654. var idx = this.s.criteria.length;
  2655. var criteria = new Criteria(this.s.dt, this.s.opts, this.s.topGroup, idx, this.s.depth);
  2656. criteria.populate();
  2657. // Add the new criteria to the criteria array
  2658. this.s.criteria.push({
  2659. criteria: criteria,
  2660. index: idx
  2661. });
  2662. // Rebuild it with the previous conditions for that criteria
  2663. criteria.rebuild(loadedCriteria);
  2664. this.s.criteria[idx].criteria = criteria;
  2665. this.s.topGroup.trigger('dtsb-redrawContents');
  2666. };
  2667. /**
  2668. * Checks And the criteria using AND logic
  2669. *
  2670. * @param rowData The row data to be checked against the search criteria
  2671. * @returns boolean The result of the AND search
  2672. */
  2673. Group.prototype._andSearch = function (rowData, rowIdx) {
  2674. // If there are no criteria then return true for this group
  2675. if (this.s.criteria.length === 0) {
  2676. return true;
  2677. }
  2678. for (var _i = 0, _a = this.s.criteria; _i < _a.length; _i++) {
  2679. var crit = _a[_i];
  2680. // If the criteria is not complete then skip it
  2681. if (crit.criteria instanceof Criteria && !crit.criteria.s.filled) {
  2682. continue;
  2683. }
  2684. // Otherwise if a single one fails return false
  2685. else if (!crit.criteria.search(rowData, rowIdx)) {
  2686. return false;
  2687. }
  2688. }
  2689. // If we get to here then everything has passed, so return true for the group
  2690. return true;
  2691. };
  2692. /**
  2693. * Checks And the criteria using OR logic
  2694. *
  2695. * @param rowData The row data to be checked against the search criteria
  2696. * @returns boolean The result of the OR search
  2697. */
  2698. Group.prototype._orSearch = function (rowData, rowIdx) {
  2699. // If there are no criteria in the group then return true
  2700. if (this.s.criteria.length === 0) {
  2701. return true;
  2702. }
  2703. // This will check to make sure that at least one criteria in the group is complete
  2704. var filledfound = false;
  2705. for (var _i = 0, _a = this.s.criteria; _i < _a.length; _i++) {
  2706. var crit = _a[_i];
  2707. if (crit.criteria instanceof Criteria && crit.criteria.s.filled) {
  2708. // A completed criteria has been found so set the flag
  2709. filledfound = true;
  2710. // If the search passes then return true
  2711. if (crit.criteria.search(rowData, rowIdx)) {
  2712. return true;
  2713. }
  2714. }
  2715. else if (crit.criteria instanceof Group && crit.criteria.checkFilled()) {
  2716. filledfound = true;
  2717. if (crit.criteria.search(rowData, rowIdx)) {
  2718. return true;
  2719. }
  2720. }
  2721. }
  2722. // If we get here we need to return the inverse of filledfound,
  2723. // as if any have been found and we are here then none have passed
  2724. return !filledfound;
  2725. };
  2726. /**
  2727. * Removes a criteria from the group
  2728. *
  2729. * @param criteria The criteria instance to be removed
  2730. */
  2731. Group.prototype._removeCriteria = function (criteria, group) {
  2732. if (group === void 0) { group = false; }
  2733. // If removing a criteria and there is only then then just destroy the group
  2734. if (this.s.criteria.length <= 1 && this.s.isChild) {
  2735. this.destroy();
  2736. }
  2737. else {
  2738. // Otherwise splice the given criteria out and redo the indexes
  2739. var last = void 0;
  2740. for (var i = 0; i < this.s.criteria.length; i++) {
  2741. if (this.s.criteria[i].index === criteria.s.index &&
  2742. (!group || this.s.criteria[i].criteria instanceof Group)) {
  2743. last = i;
  2744. }
  2745. }
  2746. // We want to remove the last element with the desired index, as its replacement will be inserted before it
  2747. if (last !== undefined) {
  2748. this.s.criteria.splice(last, 1);
  2749. }
  2750. for (var i = 0; i < this.s.criteria.length; i++) {
  2751. this.s.criteria[i].index = i;
  2752. this.s.criteria[i].criteria.s.index = i;
  2753. }
  2754. }
  2755. };
  2756. /**
  2757. * Sets the listeners in group for a criteria
  2758. *
  2759. * @param criteria The criteria for the listeners to be set on
  2760. */
  2761. Group.prototype._setCriteriaListeners = function (criteria) {
  2762. var _this = this;
  2763. criteria.dom["delete"]
  2764. .unbind('click')
  2765. .on('click', function () {
  2766. _this._removeCriteria(criteria);
  2767. criteria.dom.container.remove();
  2768. for (var _i = 0, _a = _this.s.criteria; _i < _a.length; _i++) {
  2769. var crit = _a[_i];
  2770. if (crit.criteria instanceof Criteria) {
  2771. crit.criteria.updateArrows(_this.s.criteria.length > 1);
  2772. }
  2773. }
  2774. criteria.destroy();
  2775. _this.s.dt.draw();
  2776. _this.s.topGroup.trigger('dtsb-redrawContents');
  2777. _this.s.topGroup.trigger('dtsb-updateTitle');
  2778. return false;
  2779. });
  2780. criteria.dom.right
  2781. .unbind('click')
  2782. .on('click', function () {
  2783. var idx = criteria.s.index;
  2784. var group = new Group(_this.s.dt, _this.s.opts, _this.s.topGroup, criteria.s.index, true, _this.s.depth + 1);
  2785. // Add the criteria that is to be moved to the new group
  2786. group.addCriteria(criteria);
  2787. // Update the details in the current groups criteria array
  2788. _this.s.criteria[idx].criteria = group;
  2789. _this.s.criteria[idx].logic = 'AND';
  2790. _this.s.topGroup.trigger('dtsb-redrawContents');
  2791. _this._setGroupListeners(group);
  2792. return false;
  2793. });
  2794. criteria.dom.left
  2795. .unbind('click')
  2796. .on('click', function () {
  2797. _this.s.toDrop = new Criteria(_this.s.dt, _this.s.opts, _this.s.topGroup, criteria.s.index);
  2798. _this.s.toDrop.s = criteria.s;
  2799. _this.s.toDrop.c = criteria.c;
  2800. _this.s.toDrop.classes = criteria.classes;
  2801. _this.s.toDrop.populate();
  2802. // The dropCriteria event mutates the reference to the index so need to store it
  2803. var index = _this.s.toDrop.s.index;
  2804. _this.dom.container.trigger('dtsb-dropCriteria');
  2805. criteria.s.index = index;
  2806. _this._removeCriteria(criteria);
  2807. // By tracking the top level group we can directly trigger a redraw on it,
  2808. // bubbling is also possible, but that is slow with deep levelled groups
  2809. _this.s.topGroup.trigger('dtsb-redrawContents');
  2810. _this.s.dt.draw();
  2811. return false;
  2812. });
  2813. };
  2814. /**
  2815. * Set's the listeners for the group clear button
  2816. */
  2817. Group.prototype._setClearListener = function () {
  2818. var _this = this;
  2819. this.dom.clear
  2820. .unbind('click')
  2821. .on('click', function () {
  2822. if (!_this.s.isChild) {
  2823. _this.dom.container.trigger('dtsb-clearContents');
  2824. return false;
  2825. }
  2826. _this.destroy();
  2827. _this.s.topGroup.trigger('dtsb-updateTitle');
  2828. _this.s.topGroup.trigger('dtsb-redrawContents');
  2829. return false;
  2830. });
  2831. };
  2832. /**
  2833. * Sets listeners for sub groups of this group
  2834. *
  2835. * @param group The sub group that the listeners are to be set on
  2836. */
  2837. Group.prototype._setGroupListeners = function (group) {
  2838. var _this = this;
  2839. // Set listeners for the new group
  2840. group.dom.add
  2841. .unbind('click')
  2842. .on('click', function () {
  2843. _this.setupLogic();
  2844. _this.dom.container.trigger('dtsb-add');
  2845. return false;
  2846. });
  2847. group.dom.container
  2848. .unbind('dtsb-add')
  2849. .on('dtsb-add', function () {
  2850. _this.setupLogic();
  2851. _this.dom.container.trigger('dtsb-add');
  2852. return false;
  2853. });
  2854. group.dom.container
  2855. .unbind('dtsb-destroy')
  2856. .on('dtsb-destroy', function () {
  2857. _this._removeCriteria(group, true);
  2858. group.dom.container.remove();
  2859. _this.setupLogic();
  2860. return false;
  2861. });
  2862. group.dom.container
  2863. .unbind('dtsb-dropCriteria')
  2864. .on('dtsb-dropCriteria', function () {
  2865. var toDrop = group.s.toDrop;
  2866. toDrop.s.index = group.s.index;
  2867. toDrop.updateArrows(_this.s.criteria.length > 1, false);
  2868. _this.addCriteria(toDrop, false);
  2869. return false;
  2870. });
  2871. group.setListeners();
  2872. };
  2873. /**
  2874. * Sets up the Group instance, setting listeners and appending elements
  2875. */
  2876. Group.prototype._setup = function () {
  2877. this.setListeners();
  2878. this.dom.add.text(this.s.dt.i18n('searchBuilder.add', this.c.i18n.add));
  2879. this.dom.logic.children().first().text(this.c.logic === 'OR'
  2880. ? this.s.dt.i18n('searchBuilder.logicOr', this.c.i18n.logicOr)
  2881. : this.s.dt.i18n('searchBuilder.logicAnd', this.c.i18n.logicAnd));
  2882. this.s.logic = this.c.logic === 'OR' ? 'OR' : 'AND';
  2883. if (this.c.greyscale) {
  2884. this.dom.logic.addClass(this.classes.greyscale);
  2885. }
  2886. this.dom.logicContainer.append(this.dom.logic).append(this.dom.clear);
  2887. // Only append the logic button immediately if this is a sub group,
  2888. // otherwise it will be prepended later when adding a criteria
  2889. if (this.s.isChild) {
  2890. this.dom.container.append(this.dom.logicContainer);
  2891. }
  2892. this.dom.container.append(this.dom.add);
  2893. };
  2894. /**
  2895. * Sets the listener for the logic button
  2896. */
  2897. Group.prototype._setLogicListener = function () {
  2898. var _this = this;
  2899. this.dom.logic
  2900. .unbind('click')
  2901. .on('click', function () {
  2902. _this._toggleLogic();
  2903. _this.s.dt.draw();
  2904. for (var _i = 0, _a = _this.s.criteria; _i < _a.length; _i++) {
  2905. var crit = _a[_i];
  2906. crit.criteria.setListeners();
  2907. }
  2908. });
  2909. };
  2910. /**
  2911. * Toggles the logic for the group
  2912. */
  2913. Group.prototype._toggleLogic = function () {
  2914. if (this.s.logic === 'OR') {
  2915. this.s.logic = 'AND';
  2916. this.dom.logic.children().first().text(this.s.dt.i18n('searchBuilder.logicAnd', this.c.i18n.logicAnd));
  2917. }
  2918. else if (this.s.logic === 'AND') {
  2919. this.s.logic = 'OR';
  2920. this.dom.logic.children().first().text(this.s.dt.i18n('searchBuilder.logicOr', this.c.i18n.logicOr));
  2921. }
  2922. };
  2923. Group.version = '1.1.0';
  2924. Group.classes = {
  2925. add: 'dtsb-add',
  2926. button: 'dtsb-button',
  2927. clearGroup: 'dtsb-clearGroup',
  2928. greyscale: 'dtsb-greyscale',
  2929. group: 'dtsb-group',
  2930. inputButton: 'dtsb-iptbtn',
  2931. logic: 'dtsb-logic',
  2932. logicContainer: 'dtsb-logicContainer'
  2933. };
  2934. Group.defaults = {
  2935. columns: true,
  2936. conditions: {
  2937. 'date': Criteria.dateConditions,
  2938. 'html': Criteria.stringConditions,
  2939. 'html-num': Criteria.numConditions,
  2940. 'html-num-fmt': Criteria.numFmtConditions,
  2941. 'luxon': Criteria.luxonDateConditions,
  2942. 'moment': Criteria.momentDateConditions,
  2943. 'num': Criteria.numConditions,
  2944. 'num-fmt': Criteria.numFmtConditions,
  2945. 'string': Criteria.stringConditions
  2946. },
  2947. depthLimit: false,
  2948. enterSearch: false,
  2949. filterChanged: undefined,
  2950. greyscale: false,
  2951. i18n: {
  2952. add: 'Add Condition',
  2953. button: {
  2954. 0: 'Search Builder',
  2955. _: 'Search Builder (%d)'
  2956. },
  2957. clearAll: 'Clear All',
  2958. condition: 'Condition',
  2959. data: 'Data',
  2960. deleteTitle: 'Delete filtering rule',
  2961. leftTitle: 'Outdent criteria',
  2962. logicAnd: 'And',
  2963. logicOr: 'Or',
  2964. rightTitle: 'Indent criteria',
  2965. title: {
  2966. 0: 'Custom Search Builder',
  2967. _: 'Custom Search Builder (%d)'
  2968. },
  2969. value: 'Value',
  2970. valueJoiner: 'and'
  2971. },
  2972. logic: 'AND',
  2973. orthogonal: {
  2974. display: 'display',
  2975. search: 'filter'
  2976. },
  2977. preDefined: false
  2978. };
  2979. return Group;
  2980. }());
  2981. var $;
  2982. var dataTable;
  2983. /**
  2984. * Sets the value of jQuery for use in the file
  2985. *
  2986. * @param jq the instance of jQuery to be set
  2987. */
  2988. function setJQuery(jq) {
  2989. $ = jq;
  2990. dataTable = jq.fn.DataTable;
  2991. }
  2992. /**
  2993. * SearchBuilder class for DataTables.
  2994. * Allows for complex search queries to be constructed and implemented on a DataTable
  2995. */
  2996. var SearchBuilder = /** @class */ (function () {
  2997. function SearchBuilder(builderSettings, opts) {
  2998. var _this = this;
  2999. // Check that the required version of DataTables is included
  3000. if (!dataTable || !dataTable.versionCheck || !dataTable.versionCheck('1.10.0')) {
  3001. throw new Error('SearchBuilder requires DataTables 1.10 or newer');
  3002. }
  3003. var table = new dataTable.Api(builderSettings);
  3004. this.classes = $.extend(true, {}, SearchBuilder.classes);
  3005. // Get options from user
  3006. this.c = $.extend(true, {}, SearchBuilder.defaults, opts);
  3007. this.dom = {
  3008. clearAll: $('<button type="button">' + table.i18n('searchBuilder.clearAll', this.c.i18n.clearAll) + '</button>')
  3009. .addClass(this.classes.clearAll)
  3010. .addClass(this.classes.button)
  3011. .attr('type', 'button'),
  3012. container: $('<div/>')
  3013. .addClass(this.classes.container),
  3014. title: $('<div/>')
  3015. .addClass(this.classes.title),
  3016. titleRow: $('<div/>')
  3017. .addClass(this.classes.titleRow),
  3018. topGroup: undefined
  3019. };
  3020. this.s = {
  3021. dt: table,
  3022. opts: opts,
  3023. search: undefined,
  3024. topGroup: undefined
  3025. };
  3026. // If searchbuilder is already defined for this table then return
  3027. if (table.settings()[0]._searchBuilder !== undefined) {
  3028. return;
  3029. }
  3030. table.settings()[0]._searchBuilder = this;
  3031. this.s.dt.one('preXhr', function (e, settings, data) {
  3032. data.searchBuilder = _this.c.preDefined !== false ? _this.c.preDefined : null;
  3033. });
  3034. // Run the remaining setup when the table is initialised
  3035. if (this.s.dt.settings()[0]._bInitComplete) {
  3036. this._setUp();
  3037. }
  3038. else {
  3039. table.one('init.dt', function () {
  3040. _this._setUp();
  3041. });
  3042. }
  3043. return this;
  3044. }
  3045. /**
  3046. * Gets the details required to rebuild the SearchBuilder as it currently is
  3047. */
  3048. // eslint upset at empty object but that is what it is
  3049. // eslint-disable-next-line @typescript-eslint/ban-types
  3050. SearchBuilder.prototype.getDetails = function () {
  3051. return this.s.topGroup.getDetails();
  3052. };
  3053. /**
  3054. * Getter for the node of the container for the searchBuilder
  3055. *
  3056. * @returns JQuery<HTMLElement> the node of the container
  3057. */
  3058. SearchBuilder.prototype.getNode = function () {
  3059. return this.dom.container;
  3060. };
  3061. /**
  3062. * Rebuilds the SearchBuilder to a state that is provided
  3063. *
  3064. * @param details The details required to perform a rebuild
  3065. */
  3066. SearchBuilder.prototype.rebuild = function (details) {
  3067. this.dom.clearAll.click();
  3068. // If there are no details to rebuild then return
  3069. if (details === undefined || details === null) {
  3070. return this;
  3071. }
  3072. this.s.topGroup.rebuild(details);
  3073. this.s.dt.draw(false);
  3074. this.s.topGroup.setListeners();
  3075. return this;
  3076. };
  3077. /**
  3078. * Applies the defaults to preDefined criteria
  3079. *
  3080. * @param preDef the array of criteria to be processed.
  3081. */
  3082. SearchBuilder.prototype._applyPreDefDefaults = function (preDef) {
  3083. var _this = this;
  3084. if (preDef.criteria !== undefined && preDef.logic === undefined) {
  3085. preDef.logic = 'AND';
  3086. }
  3087. var _loop_1 = function (crit) {
  3088. // Apply the defaults to any further criteria
  3089. if (crit.criteria !== undefined) {
  3090. crit = this_1._applyPreDefDefaults(crit);
  3091. }
  3092. else {
  3093. this_1.s.dt.columns().every(function (index) {
  3094. if (_this.s.dt.settings()[0].aoColumns[index].sTitle === crit.data) {
  3095. crit.dataIdx = index;
  3096. }
  3097. });
  3098. }
  3099. };
  3100. var this_1 = this;
  3101. for (var _i = 0, _a = preDef.criteria; _i < _a.length; _i++) {
  3102. var crit = _a[_i];
  3103. _loop_1(crit);
  3104. }
  3105. return preDef;
  3106. };
  3107. /**
  3108. * Set's up the SearchBuilder
  3109. */
  3110. SearchBuilder.prototype._setUp = function (loadState) {
  3111. var _this = this;
  3112. if (loadState === void 0) { loadState = true; }
  3113. // Register an Api method for getting the column type
  3114. $.fn.DataTable.Api.registerPlural('columns().type()', 'column().type()', function (selector, opts) {
  3115. return this.iterator('column', function (settings, column) {
  3116. return settings.aoColumns[column].sType;
  3117. }, 1);
  3118. });
  3119. // Check that DateTime is included, If not need to check if it could be used
  3120. // eslint-disable-next-line no-extra-parens
  3121. if (!dataTable.DateTime) {
  3122. var types = this.s.dt.columns().type().toArray();
  3123. var columnIdxs = this.s.dt.columns().toArray();
  3124. // If the types are not yet set then draw to see if they can be retrieved then
  3125. if (types === undefined) {
  3126. this.s.dt.draw(false);
  3127. types = this.s.dt.columns().type().toArray();
  3128. }
  3129. for (var i = 0; i < columnIdxs[0].length; i++) {
  3130. var column = columnIdxs[0][i];
  3131. var type = types[column];
  3132. if (
  3133. // Check if this column can be filtered
  3134. (this.c.columns === true ||
  3135. Array.isArray(this.c.columns) &&
  3136. this.c.columns.includes(i)) &&
  3137. // Check if the type is one of the restricted types
  3138. (type.includes('date') ||
  3139. type.includes('moment') ||
  3140. type.includes('luxon'))) {
  3141. alert('SearchBuilder Requires DateTime when used with dates.');
  3142. throw new Error('SearchBuilder requires DateTime');
  3143. }
  3144. }
  3145. }
  3146. this.s.topGroup = new Group(this.s.dt, this.c, undefined);
  3147. this._setClearListener();
  3148. this.s.dt.on('stateSaveParams', function (e, settings, data) {
  3149. data.searchBuilder = _this.getDetails();
  3150. data.page = _this.s.dt.page();
  3151. });
  3152. this._build();
  3153. if (loadState) {
  3154. var loadedState = this.s.dt.state.loaded();
  3155. // If the loaded State is not null rebuild based on it for statesave
  3156. if (loadedState !== null && loadedState.searchBuilder !== undefined) {
  3157. this.s.topGroup.rebuild(loadedState.searchBuilder);
  3158. this.s.topGroup.dom.container.trigger('dtsb-redrawContents');
  3159. this.s.dt.page(loadedState.page).draw('page');
  3160. this.s.topGroup.setListeners();
  3161. }
  3162. // Otherwise load any predefined options
  3163. else if (this.c.preDefined !== false) {
  3164. this.c.preDefined = this._applyPreDefDefaults(this.c.preDefined);
  3165. this.rebuild(this.c.preDefined);
  3166. }
  3167. }
  3168. this._setEmptyListener();
  3169. this.s.dt.state.save();
  3170. this.s.dt.on('preXhr', function (e, settings, data) {
  3171. data.searchBuilder = _this.getDetails();
  3172. });
  3173. };
  3174. /**
  3175. * Updates the title of the SearchBuilder
  3176. *
  3177. * @param count the number of filters in the SearchBuilder
  3178. */
  3179. SearchBuilder.prototype._updateTitle = function (count) {
  3180. this.dom.title.html(this.s.dt.i18n('searchBuilder.title', this.c.i18n.title, count));
  3181. };
  3182. /**
  3183. * Builds all of the dom elements together
  3184. */
  3185. SearchBuilder.prototype._build = function () {
  3186. var _this = this;
  3187. // Empty and setup the container
  3188. this.dom.clearAll.remove();
  3189. this.dom.container.empty();
  3190. var count = this.s.topGroup.count();
  3191. this._updateTitle(count);
  3192. this.dom.titleRow.append(this.dom.title);
  3193. this.dom.container.append(this.dom.titleRow);
  3194. this.dom.topGroup = this.s.topGroup.getNode();
  3195. this.dom.container.append(this.dom.topGroup);
  3196. this._setRedrawListener();
  3197. var tableNode = this.s.dt.table(0).node();
  3198. if (!$.fn.dataTable.ext.search.includes(this.s.search)) {
  3199. // Custom search function for SearchBuilder
  3200. this.s.search = function (settings, searchData, dataIndex, origData) {
  3201. if (settings.nTable !== tableNode) {
  3202. return true;
  3203. }
  3204. return _this.s.topGroup.search(searchData, dataIndex);
  3205. };
  3206. // Add SearchBuilder search function to the dataTables search array
  3207. $.fn.dataTable.ext.search.push(this.s.search);
  3208. }
  3209. this.s.dt.on('destroy.dt', function () {
  3210. _this.dom.container.remove();
  3211. _this.dom.clearAll.remove();
  3212. var searchIdx = $.fn.dataTable.ext.search.indexOf(_this.s.search);
  3213. while (searchIdx !== -1) {
  3214. $.fn.dataTable.ext.search.splice(searchIdx, 1);
  3215. searchIdx = $.fn.dataTable.ext.search.indexOf(_this.s.search);
  3216. }
  3217. });
  3218. };
  3219. /**
  3220. * Checks if the clearAll button should be added or not
  3221. */
  3222. SearchBuilder.prototype._checkClear = function () {
  3223. if (this.s.topGroup.s.criteria.length > 0) {
  3224. this.dom.clearAll.insertAfter(this.dom.title);
  3225. this._setClearListener();
  3226. }
  3227. else {
  3228. this.dom.clearAll.remove();
  3229. }
  3230. };
  3231. /**
  3232. * Update the count in the title/button
  3233. *
  3234. * @param count Number of filters applied
  3235. */
  3236. SearchBuilder.prototype._filterChanged = function (count) {
  3237. var fn = this.c.filterChanged;
  3238. if (typeof fn === 'function') {
  3239. fn(count, this.s.dt.i18n('searchBuilder.button', this.c.i18n.button, count));
  3240. }
  3241. };
  3242. /**
  3243. * Set the listener for the clear button
  3244. */
  3245. SearchBuilder.prototype._setClearListener = function () {
  3246. var _this = this;
  3247. this.dom.clearAll.unbind('click');
  3248. this.dom.clearAll.on('click', function () {
  3249. _this.s.topGroup = new Group(_this.s.dt, _this.c, undefined);
  3250. _this._build();
  3251. _this.s.dt.draw();
  3252. _this.s.topGroup.setListeners();
  3253. _this.dom.clearAll.remove();
  3254. _this._setEmptyListener();
  3255. _this._filterChanged(0);
  3256. return false;
  3257. });
  3258. };
  3259. /**
  3260. * Set the listener for the Redraw event
  3261. */
  3262. SearchBuilder.prototype._setRedrawListener = function () {
  3263. var _this = this;
  3264. this.s.topGroup.dom.container.unbind('dtsb-redrawContents');
  3265. this.s.topGroup.dom.container.on('dtsb-redrawContents', function () {
  3266. _this._checkClear();
  3267. _this.s.topGroup.redrawContents();
  3268. _this.s.topGroup.setupLogic();
  3269. _this._setEmptyListener();
  3270. var count = _this.s.topGroup.count();
  3271. _this._updateTitle(count);
  3272. _this._filterChanged(count);
  3273. _this.s.dt.state.save();
  3274. });
  3275. this.s.topGroup.dom.container.unbind('dtsb-redrawLogic');
  3276. this.s.topGroup.dom.container.on('dtsb-redrawLogic', function () {
  3277. _this.s.topGroup.redrawLogic();
  3278. var count = _this.s.topGroup.count();
  3279. _this._updateTitle(count);
  3280. _this._filterChanged(count);
  3281. });
  3282. this.s.topGroup.dom.container.unbind('dtsb-add');
  3283. this.s.topGroup.dom.container.on('dtsb-add', function () {
  3284. var count = _this.s.topGroup.count();
  3285. _this._updateTitle(count);
  3286. _this._filterChanged(count);
  3287. });
  3288. this.s.dt.on('postEdit postCreate postRemove', function () {
  3289. _this.s.topGroup.redrawContents();
  3290. });
  3291. this.s.topGroup.dom.container.unbind('dtsb-clearContents');
  3292. this.s.topGroup.dom.container.on('dtsb-clearContents', function () {
  3293. _this._setUp(false);
  3294. _this._filterChanged(0);
  3295. _this.s.dt.draw();
  3296. });
  3297. this.s.topGroup.dom.container.on('dtsb-updateTitle', function () {
  3298. var count = _this.s.topGroup.count();
  3299. _this._updateTitle(count);
  3300. _this._filterChanged(count);
  3301. });
  3302. };
  3303. /**
  3304. * Sets listeners to check whether clearAll should be added or removed
  3305. */
  3306. SearchBuilder.prototype._setEmptyListener = function () {
  3307. var _this = this;
  3308. this.s.topGroup.dom.add.on('click', function () {
  3309. _this._checkClear();
  3310. });
  3311. this.s.topGroup.dom.container.on('dtsb-destroy', function () {
  3312. _this.dom.clearAll.remove();
  3313. });
  3314. };
  3315. SearchBuilder.version = '1.1.0';
  3316. SearchBuilder.classes = {
  3317. button: 'dtsb-button',
  3318. clearAll: 'dtsb-clearAll',
  3319. container: 'dtsb-searchBuilder',
  3320. inputButton: 'dtsb-iptbtn',
  3321. title: 'dtsb-title',
  3322. titleRow: 'dtsb-titleRow'
  3323. };
  3324. SearchBuilder.defaults = {
  3325. columns: true,
  3326. conditions: {
  3327. 'date': Criteria.dateConditions,
  3328. 'html': Criteria.stringConditions,
  3329. 'html-num': Criteria.numConditions,
  3330. 'html-num-fmt': Criteria.numFmtConditions,
  3331. 'luxon': Criteria.luxonDateConditions,
  3332. 'moment': Criteria.momentDateConditions,
  3333. 'num': Criteria.numConditions,
  3334. 'num-fmt': Criteria.numFmtConditions,
  3335. 'string': Criteria.stringConditions
  3336. },
  3337. depthLimit: false,
  3338. enterSearch: false,
  3339. filterChanged: undefined,
  3340. greyscale: false,
  3341. i18n: {
  3342. add: 'Add Condition',
  3343. button: {
  3344. 0: 'Search Builder',
  3345. _: 'Search Builder (%d)'
  3346. },
  3347. clearAll: 'Clear All',
  3348. condition: 'Condition',
  3349. conditions: {
  3350. array: {
  3351. contains: 'Contains',
  3352. empty: 'Empty',
  3353. equals: 'Equals',
  3354. not: 'Not',
  3355. notEmpty: 'Not Empty',
  3356. without: 'Without'
  3357. },
  3358. date: {
  3359. after: 'After',
  3360. before: 'Before',
  3361. between: 'Between',
  3362. empty: 'Empty',
  3363. equals: 'Equals',
  3364. not: 'Not',
  3365. notBetween: 'Not Between',
  3366. notEmpty: 'Not Empty'
  3367. },
  3368. // eslint-disable-next-line id-blacklist
  3369. number: {
  3370. between: 'Between',
  3371. empty: 'Empty',
  3372. equals: 'Equals',
  3373. gt: 'Greater Than',
  3374. gte: 'Greater Than Equal To',
  3375. lt: 'Less Than',
  3376. lte: 'Less Than Equal To',
  3377. not: 'Not',
  3378. notBetween: 'Not Between',
  3379. notEmpty: 'Not Empty'
  3380. },
  3381. // eslint-disable-next-line id-blacklist
  3382. string: {
  3383. contains: 'Contains',
  3384. empty: 'Empty',
  3385. endsWith: 'Ends With',
  3386. equals: 'Equals',
  3387. not: 'Not',
  3388. notEmpty: 'Not Empty',
  3389. startsWith: 'Starts With'
  3390. }
  3391. },
  3392. data: 'Data',
  3393. deleteTitle: 'Delete filtering rule',
  3394. leftTitle: 'Outdent criteria',
  3395. logicAnd: 'And',
  3396. logicOr: 'Or',
  3397. rightTitle: 'Indent criteria',
  3398. title: {
  3399. 0: 'Custom Search Builder',
  3400. _: 'Custom Search Builder (%d)'
  3401. },
  3402. value: 'Value',
  3403. valueJoiner: 'and'
  3404. },
  3405. logic: 'AND',
  3406. orthogonal: {
  3407. display: 'display',
  3408. search: 'filter'
  3409. },
  3410. preDefined: false
  3411. };
  3412. return SearchBuilder;
  3413. }());
  3414. /*! SearchBuilder 1.1.0
  3415. * ©SpryMedia Ltd - datatables.net/license/mit
  3416. */
  3417. // DataTables extensions common UMD. Note that this allows for AMD, CommonJS
  3418. // (with window and jQuery being allowed as parameters to the returned
  3419. // function) or just default browser loading.
  3420. (function (factory) {
  3421. if (typeof define === 'function' && define.amd) {
  3422. // AMD
  3423. define(['jquery', 'datatables.net'], function ($) {
  3424. return factory($, window, document);
  3425. });
  3426. }
  3427. else if (typeof exports === 'object') {
  3428. // CommonJS
  3429. module.exports = function (root, $) {
  3430. if (!root) {
  3431. root = window;
  3432. }
  3433. if (!$ || !$.fn.dataTable) {
  3434. // eslint-disable-next-line @typescript-eslint/no-var-requires
  3435. $ = require('datatables.net')(root, $).$;
  3436. }
  3437. return factory($, root, root.document);
  3438. };
  3439. }
  3440. else {
  3441. // Browser - assume jQuery has already been loaded
  3442. // eslint-disable-next-line no-extra-parens
  3443. factory(window.jQuery, window, document);
  3444. }
  3445. }(function ($, window, document) {
  3446. setJQuery($);
  3447. setJQuery$1($);
  3448. setJQuery$2($);
  3449. var dataTable = $.fn.dataTable;
  3450. // eslint-disable-next-line no-extra-parens
  3451. $.fn.dataTable.SearchBuilder = SearchBuilder;
  3452. // eslint-disable-next-line no-extra-parens
  3453. $.fn.DataTable.SearchBuilder = SearchBuilder;
  3454. // eslint-disable-next-line no-extra-parens
  3455. $.fn.dataTable.Group = Group;
  3456. // eslint-disable-next-line no-extra-parens
  3457. $.fn.DataTable.Group = Group;
  3458. // eslint-disable-next-line no-extra-parens
  3459. $.fn.dataTable.Criteria = Criteria;
  3460. // eslint-disable-next-line no-extra-parens
  3461. $.fn.DataTable.Criteria = Criteria;
  3462. // eslint-disable-next-line no-extra-parens
  3463. var apiRegister = $.fn.dataTable.Api.register;
  3464. // Set up object for plugins
  3465. $.fn.dataTable.ext.searchBuilder = {
  3466. conditions: {}
  3467. };
  3468. $.fn.dataTable.ext.buttons.searchBuilder = {
  3469. action: function (e, dt, node, config) {
  3470. e.stopPropagation();
  3471. this.popover(config._searchBuilder.getNode(), {
  3472. align: 'dt-container'
  3473. });
  3474. // Need to redraw the contents to calculate the correct positions for the elements
  3475. if (config._searchBuilder.s.topGroup !== undefined) {
  3476. config._searchBuilder.s.topGroup.dom.container.trigger('dtsb-redrawContents');
  3477. }
  3478. },
  3479. config: {},
  3480. init: function (dt, node, config) {
  3481. var sb = new $.fn.dataTable.SearchBuilder(dt, $.extend({
  3482. filterChanged: function (count, text) {
  3483. dt.button(node).text(text);
  3484. }
  3485. }, config.config));
  3486. dt.button(node).text(config.text || dt.i18n('searchBuilder.button', sb.c.i18n.button, 0));
  3487. config._searchBuilder = sb;
  3488. },
  3489. text: null
  3490. };
  3491. apiRegister('searchBuilder.getDetails()', function () {
  3492. var ctx = this.context[0];
  3493. // If SearchBuilder has not been initialised on this instance then return
  3494. return ctx._searchBuilder ?
  3495. ctx._searchBuilder.getDetails() :
  3496. null;
  3497. });
  3498. apiRegister('searchBuilder.rebuild()', function (details) {
  3499. var ctx = this.context[0];
  3500. // If SearchBuilder has not been initialised on this instance then return
  3501. if (ctx._searchBuilder === undefined) {
  3502. return null;
  3503. }
  3504. ctx._searchBuilder.rebuild(details);
  3505. return this;
  3506. });
  3507. apiRegister('searchBuilder.container()', function () {
  3508. var ctx = this.context[0];
  3509. // If SearchBuilder has not been initialised on this instance then return
  3510. return ctx._searchBuilder ?
  3511. ctx._searchBuilder.getNode() :
  3512. null;
  3513. });
  3514. /**
  3515. * Init function for SearchBuilder
  3516. *
  3517. * @param settings the settings to be applied
  3518. * @param options the options for SearchBuilder
  3519. * @returns JQUERY<HTMLElement> Returns the node of the SearchBuilder
  3520. */
  3521. function _init(settings, options) {
  3522. var api = new dataTable.Api(settings);
  3523. var opts = options
  3524. ? options
  3525. : api.init().searchBuilder || dataTable.defaults.searchBuilder;
  3526. var searchBuilder = new SearchBuilder(api, opts);
  3527. var node = searchBuilder.getNode();
  3528. return node;
  3529. }
  3530. // Attach a listener to the document which listens for DataTables initialisation
  3531. // events so we can automatically initialise
  3532. $(document).on('preInit.dt.dtsp', function (e, settings, json) {
  3533. if (e.namespace !== 'dt') {
  3534. return;
  3535. }
  3536. if (settings.oInit.searchBuilder ||
  3537. dataTable.defaults.searchBuilder) {
  3538. if (!settings._searchBuilder) {
  3539. _init(settings);
  3540. }
  3541. }
  3542. });
  3543. // DataTables `dom` feature option
  3544. dataTable.ext.feature.push({
  3545. cFeature: 'Q',
  3546. fnInit: _init
  3547. });
  3548. // DataTables 2 layout feature
  3549. if (dataTable.ext.features) {
  3550. dataTable.ext.features.register('searchBuilder', _init);
  3551. }
  3552. }));
  3553. }());