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

dataTables.searchBuilder.js 170KB

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