dataTables.searchPanes.js 158 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363
  1. /*! SearchPanes 2.0.2
  2. * 2019-2022 SpryMedia Ltd - datatables.net/license
  3. */
  4. (function () {
  5. 'use strict';
  6. var $$4;
  7. var dataTable$1;
  8. function setJQuery$4(jq) {
  9. $$4 = jq;
  10. dataTable$1 = jq.fn.dataTable;
  11. }
  12. var SearchPane = /** @class */ (function () {
  13. /**
  14. * Creates the panes, sets up the search function
  15. *
  16. * @param paneSettings The settings for the searchPanes
  17. * @param opts The options for the default features
  18. * @param index the index of the column for this pane
  19. * @param panesContainer The overall container for SearchPanes that this pane will be attached to
  20. * @param panes The custom pane settings if this is a custom pane
  21. * @returns {object} the pane that has been created, including the table and the index of the pane
  22. */
  23. function SearchPane(paneSettings, opts, index, panesContainer, panes) {
  24. var _this = this;
  25. if (panes === void 0) { panes = null; }
  26. // Check that the required version of DataTables is included
  27. if (!dataTable$1 || !dataTable$1.versionCheck || !dataTable$1.versionCheck('1.10.0')) {
  28. throw new Error('SearchPane requires DataTables 1.10 or newer');
  29. }
  30. // Check that Select is included
  31. // eslint-disable-next-line no-extra-parens
  32. if (!dataTable$1.select) {
  33. throw new Error('SearchPane requires Select');
  34. }
  35. var table = new dataTable$1.Api(paneSettings);
  36. this.classes = $$4.extend(true, {}, SearchPane.classes);
  37. // Get options from user
  38. this.c = $$4.extend(true, {}, SearchPane.defaults, opts);
  39. if (opts && opts.hideCount && opts.viewCount === undefined) {
  40. this.c.viewCount = !this.c.hideCount;
  41. }
  42. var rowLength = table.columns().eq(0).toArray().length;
  43. this.s = {
  44. colExists: index < rowLength,
  45. colOpts: undefined,
  46. customPaneSettings: panes,
  47. displayed: false,
  48. dt: table,
  49. dtPane: undefined,
  50. firstSet: true,
  51. index: index,
  52. indexes: [],
  53. listSet: false,
  54. name: undefined,
  55. rowData: {
  56. arrayFilter: [],
  57. arrayOriginal: [],
  58. bins: {},
  59. binsOriginal: {},
  60. filterMap: new Map(),
  61. totalOptions: 0
  62. },
  63. scrollTop: 0,
  64. searchFunction: undefined,
  65. selections: [],
  66. serverSelect: [],
  67. serverSelecting: false,
  68. tableLength: null,
  69. updating: false
  70. };
  71. this.s.colOpts = this.s.colExists ? this._getOptions() : this._getBonusOptions();
  72. this.dom = {
  73. buttonGroup: $$4('<div/>').addClass(this.classes.buttonGroup),
  74. clear: $$4('<button type="button">&#215;</button>')
  75. .attr('disabled', 'true')
  76. .addClass(this.classes.disabledButton)
  77. .addClass(this.classes.paneButton)
  78. .addClass(this.classes.clearButton)
  79. .html(this.s.dt.i18n('searchPanes.clearPane', this.c.i18n.clearPane)),
  80. collapseButton: $$4('<button type="button"><span class="' + this.classes.caret + '">&#x5e;</span></button>')
  81. .addClass(this.classes.paneButton)
  82. .addClass(this.classes.collapseButton),
  83. container: $$4('<div/>')
  84. .addClass(this.classes.container)
  85. .addClass(this.s.colOpts.className)
  86. .addClass(this.classes.layout +
  87. (parseInt(this.c.layout.split('-')[1], 10) < 10 ?
  88. this.c.layout :
  89. this.c.layout.split('-')[0] + '-9'))
  90. .addClass(this.s.customPaneSettings && this.s.customPaneSettings.className
  91. ? this.s.customPaneSettings.className
  92. : ''),
  93. countButton: $$4('<button type="button"></button>')
  94. .addClass(this.classes.paneButton)
  95. .addClass(this.classes.countButton),
  96. dtP: $$4('<table><thead><tr><th>' +
  97. (this.s.colExists
  98. ? $$4(this.s.dt.column(this.s.index).header()).text()
  99. : this.s.customPaneSettings.header || 'Custom Pane') + '</th><th/></tr></thead></table>'),
  100. lower: $$4('<div/>').addClass(this.classes.subRow2).addClass(this.classes.narrowButton),
  101. nameButton: $$4('<button type="button"></button>')
  102. .addClass(this.classes.paneButton)
  103. .addClass(this.classes.nameButton),
  104. panesContainer: panesContainer,
  105. searchBox: $$4('<input/>').addClass(this.classes.paneInputButton).addClass(this.classes.search),
  106. searchButton: $$4('<button type = "button"/>')
  107. .addClass(this.classes.searchIcon)
  108. .addClass(this.classes.paneButton),
  109. searchCont: $$4('<div/>').addClass(this.classes.searchCont),
  110. searchLabelCont: $$4('<div/>').addClass(this.classes.searchLabelCont),
  111. topRow: $$4('<div/>').addClass(this.classes.topRow),
  112. upper: $$4('<div/>').addClass(this.classes.subRow1).addClass(this.classes.narrowSearch)
  113. };
  114. // Set the value of name incase ordering is desired
  115. if (this.s.colOpts.name) {
  116. this.s.name = this.s.colOpts.name;
  117. }
  118. else if (this.s.customPaneSettings && this.s.customPaneSettings.name) {
  119. this.s.name = this.s.customPaneSettings.name;
  120. }
  121. else {
  122. this.s.name = this.s.colExists ?
  123. $$4(this.s.dt.column(this.s.index).header()).text() :
  124. this.s.customPaneSettings.header || 'Custom Pane';
  125. }
  126. var tableNode = this.s.dt.table(0).node();
  127. // Custom search function for table
  128. this.s.searchFunction = function (settings, searchData, dataIndex) {
  129. // If no data has been selected then show all
  130. if (_this.s.selections.length === 0) {
  131. return true;
  132. }
  133. if (settings.nTable !== tableNode) {
  134. return true;
  135. }
  136. var filter = null;
  137. if (_this.s.colExists) {
  138. // Get the current filtered data
  139. filter = searchData[_this.s.index];
  140. if (_this.s.colOpts.orthogonal.filter !== 'filter') {
  141. // get the filter value from the map
  142. filter = _this.s.rowData.filterMap.get(dataIndex);
  143. if (filter instanceof $$4.fn.dataTable.Api) {
  144. // eslint-disable-next-line no-extra-parens
  145. filter = filter.toArray();
  146. }
  147. }
  148. }
  149. return _this._search(filter, dataIndex);
  150. };
  151. $$4.fn.dataTable.ext.search.push(this.s.searchFunction);
  152. // If the clear button for this pane is clicked clear the selections
  153. if (this.c.clear) {
  154. this.dom.clear.on('click.dtsp', function () {
  155. var searches = _this.dom.container.find('.' + _this.classes.search.replace(/\s+/g, '.'));
  156. searches.each(function () {
  157. $$4(this).val('').trigger('input');
  158. });
  159. _this.clearPane();
  160. });
  161. }
  162. // Sometimes the top row of the panes containing the search box and ordering buttons appears
  163. // weird if the width of the panes is lower than expected, this fixes the design.
  164. // Equally this may occur when the table is resized.
  165. this.s.dt.on('draw.dtsp', function () { return _this.adjustTopRow(); });
  166. this.s.dt.on('buttons-action.dtsp', function () { return _this.adjustTopRow(); });
  167. // When column-reorder is present and the columns are moved, it is necessary to
  168. // reassign all of the panes indexes to the new index of the column.
  169. this.s.dt.on('column-reorder.dtsp', function (e, settings, details) {
  170. _this.s.index = details.mapping[_this.s.index];
  171. });
  172. return this;
  173. }
  174. /**
  175. * Adds a row to the panes table
  176. *
  177. * @param display the value to be displayed to the user
  178. * @param filter the value to be filtered on when searchpanes is implemented
  179. * @param shown the number of rows in the table that are currently visible matching this criteria
  180. * @param total the total number of rows in the table that match this criteria
  181. * @param sort the value to be sorted in the pane table
  182. * @param type the value of which the type is to be derived from
  183. */
  184. SearchPane.prototype.addRow = function (display, filter, sort, type, className, total, shown) {
  185. if (!total) {
  186. total = this.s.rowData.bins[filter] ?
  187. this.s.rowData.bins[filter] :
  188. 0;
  189. }
  190. if (!shown) {
  191. shown = this._getShown(filter);
  192. }
  193. var index;
  194. for (var _i = 0, _a = this.s.indexes; _i < _a.length; _i++) {
  195. var entry = _a[_i];
  196. if (entry.filter === filter) {
  197. index = entry.index;
  198. }
  199. }
  200. if (index === undefined) {
  201. index = this.s.indexes.length;
  202. this.s.indexes.push({ filter: filter, index: index });
  203. }
  204. return this.s.dtPane.row.add({
  205. className: className,
  206. display: display !== '' ?
  207. display :
  208. this.emptyMessage(),
  209. filter: filter,
  210. index: index,
  211. shown: shown,
  212. sort: sort,
  213. total: total,
  214. type: type
  215. });
  216. };
  217. /**
  218. * Adjusts the layout of the top row when the screen is resized
  219. */
  220. SearchPane.prototype.adjustTopRow = function () {
  221. var subContainers = this.dom.container.find('.' + this.classes.subRowsContainer.replace(/\s+/g, '.'));
  222. var subRow1 = this.dom.container.find('.' + this.classes.subRow1.replace(/\s+/g, '.'));
  223. var subRow2 = this.dom.container.find('.' + this.classes.subRow2.replace(/\s+/g, '.'));
  224. var topRow = this.dom.container.find('.' + this.classes.topRow.replace(/\s+/g, '.'));
  225. // If the width is 0 then it is safe to assume that the pane has not yet been displayed.
  226. // Even if it has, if the width is 0 it won't make a difference if it has the narrow class or not
  227. if (($$4(subContainers[0]).width() < 252 || $$4(topRow[0]).width() < 252) && $$4(subContainers[0]).width() !== 0) {
  228. $$4(subContainers[0]).addClass(this.classes.narrow);
  229. $$4(subRow1[0]).addClass(this.classes.narrowSub).removeClass(this.classes.narrowSearch);
  230. $$4(subRow2[0]).addClass(this.classes.narrowSub).removeClass(this.classes.narrowButton);
  231. }
  232. else {
  233. $$4(subContainers[0]).removeClass(this.classes.narrow);
  234. $$4(subRow1[0]).removeClass(this.classes.narrowSub).addClass(this.classes.narrowSearch);
  235. $$4(subRow2[0]).removeClass(this.classes.narrowSub).addClass(this.classes.narrowButton);
  236. }
  237. };
  238. /**
  239. * In the case of a rebuild there is potential for new data to have been included or removed
  240. * so all of the rowData must be reset as a precaution.
  241. */
  242. SearchPane.prototype.clearData = function () {
  243. this.s.rowData = {
  244. arrayFilter: [],
  245. arrayOriginal: [],
  246. bins: {},
  247. binsOriginal: {},
  248. filterMap: new Map(),
  249. totalOptions: 0
  250. };
  251. };
  252. /**
  253. * Clear the selections in the pane
  254. */
  255. SearchPane.prototype.clearPane = function () {
  256. // Deselect all rows which are selected and update the table and filter count.
  257. this.s.dtPane.rows({ selected: true }).deselect();
  258. this.updateTable();
  259. return this;
  260. };
  261. /**
  262. * Collapses the pane so that only the header is displayed
  263. */
  264. SearchPane.prototype.collapse = function () {
  265. var _this = this;
  266. if (!this.s.displayed ||
  267. (
  268. // If collapsing is disabled globally, and not enabled specifically for this column
  269. !this.c.collapse && this.s.colOpts.collapse !== true ||
  270. // OR, collapsing could be enabled globally and this column specifically
  271. // is not to be collapsed.
  272. // We can't just take !this.s.colOpts.collapse here as if it is undefined
  273. // then the global should be used
  274. this.s.colOpts.collapse === false)) {
  275. return;
  276. }
  277. $$4(this.s.dtPane.table().container()).addClass(this.classes.hidden);
  278. this.dom.topRow.addClass(this.classes.bordered);
  279. this.dom.nameButton.addClass(this.classes.disabledButton);
  280. this.dom.countButton.addClass(this.classes.disabledButton);
  281. this.dom.searchButton.addClass(this.classes.disabledButton);
  282. this.dom.collapseButton.addClass(this.classes.rotated);
  283. this.dom.topRow.one('click.dtsp', function () { return _this.show(); });
  284. };
  285. /**
  286. * Strips all of the SearchPanes elements from the document and turns all of the listeners for the buttons off
  287. */
  288. SearchPane.prototype.destroy = function () {
  289. if (this.s.dtPane) {
  290. this.s.dtPane.off('.dtsp');
  291. }
  292. this.s.dt.off('.dtsp');
  293. this.dom.clear.off('.dtsp');
  294. this.dom.nameButton.off('.dtsp');
  295. this.dom.countButton.off('.dtsp');
  296. this.dom.searchButton.off('.dtsp');
  297. this.dom.collapseButton.off('.dtsp');
  298. $$4(this.s.dt.table().node()).off('.dtsp');
  299. this.dom.container.detach();
  300. var searchIdx = $$4.fn.dataTable.ext.search.indexOf(this.s.searchFunction);
  301. while (searchIdx !== -1) {
  302. $$4.fn.dataTable.ext.search.splice(searchIdx, 1);
  303. searchIdx = $$4.fn.dataTable.ext.search.indexOf(this.s.searchFunction);
  304. }
  305. // If the datatables have been defined for the panes then also destroy these
  306. if (this.s.dtPane) {
  307. this.s.dtPane.destroy();
  308. }
  309. this.s.listSet = false;
  310. };
  311. /**
  312. * Getting the legacy message is a little complex due a legacy parameter
  313. */
  314. SearchPane.prototype.emptyMessage = function () {
  315. var def = this.c.i18n.emptyMessage;
  316. // Legacy parameter support
  317. if (this.c.emptyMessage) {
  318. def = this.c.emptyMessage;
  319. }
  320. // Override per column
  321. if (this.s.colOpts.emptyMessage !== false && this.s.colOpts.emptyMessage !== null) {
  322. def = this.s.colOpts.emptyMessage;
  323. }
  324. return this.s.dt.i18n('searchPanes.emptyMessage', def);
  325. };
  326. /**
  327. * Updates the number of filters that have been applied in the title
  328. */
  329. SearchPane.prototype.getPaneCount = function () {
  330. return this.s.dtPane ?
  331. this.s.dtPane.rows({ selected: true }).data().toArray().length :
  332. 0;
  333. };
  334. /**
  335. * Rebuilds the panes from the start having deleted the old ones
  336. *
  337. * @param? dataIn data to be used in buildPane
  338. * @param? maintainSelection Whether the current selections are to be maintained over rebuild
  339. */
  340. SearchPane.prototype.rebuildPane = function (dataIn, maintainSelection) {
  341. if (dataIn === void 0) { dataIn = null; }
  342. if (maintainSelection === void 0) { maintainSelection = false; }
  343. this.clearData();
  344. var selectedRows = [];
  345. this.s.serverSelect = [];
  346. var prevEl = null;
  347. // When rebuilding strip all of the HTML Elements out of the container and start from scratch
  348. if (this.s.dtPane) {
  349. if (maintainSelection) {
  350. if (!this.s.dt.page.info().serverSide) {
  351. selectedRows = this.s.dtPane.rows({ selected: true }).data().toArray();
  352. }
  353. else {
  354. this.s.serverSelect = this.s.dtPane.rows({ selected: true }).data().toArray();
  355. }
  356. }
  357. this.s.dtPane.clear().destroy();
  358. prevEl = this.dom.container.prev();
  359. this.destroy();
  360. this.s.dtPane = undefined;
  361. $$4.fn.dataTable.ext.search.push(this.s.searchFunction);
  362. }
  363. this.dom.container.removeClass(this.classes.hidden);
  364. this.s.displayed = false;
  365. this._buildPane(!this.s.dt.page.info().serverSide ?
  366. selectedRows :
  367. this.s.serverSelect, dataIn, prevEl);
  368. return this;
  369. };
  370. /**
  371. * Resizes the pane based on the layout that is passed in
  372. *
  373. * @param layout the layout to be applied to this pane
  374. */
  375. SearchPane.prototype.resize = function (layout) {
  376. this.c.layout = layout;
  377. this.dom.container
  378. .removeClass()
  379. .addClass(this.classes.show)
  380. .addClass(this.classes.container)
  381. .addClass(this.s.colOpts.className)
  382. .addClass(this.classes.layout +
  383. (parseInt(layout.split('-')[1], 10) < 10 ?
  384. layout :
  385. layout.split('-')[0] + '-9'))
  386. .addClass(this.s.customPaneSettings !== null && this.s.customPaneSettings.className
  387. ? this.s.customPaneSettings.className
  388. : '');
  389. this.adjustTopRow();
  390. };
  391. /**
  392. * Sets the listeners for the pane.
  393. *
  394. * Having it in it's own function makes it easier to only set them once
  395. */
  396. SearchPane.prototype.setListeners = function () {
  397. var _this = this;
  398. if (!this.s.dtPane) {
  399. return;
  400. }
  401. this.s.dtPane.select.style(this.s.colOpts.dtOpts && this.s.colOpts.dtOpts.select && this.s.colOpts.dtOpts.select.style
  402. ? this.s.colOpts.dtOpts.select.style
  403. : this.c.dtOpts && this.c.dtOpts.select && this.c.dtOpts.select.style
  404. ? this.c.dtOpts.select.style
  405. : 'os');
  406. // When an item is selected on the pane, add these to the array which holds selected items.
  407. // Custom search will perform.
  408. this.s.dtPane.off('select.dtsp').on('select.dtsp', function () {
  409. clearTimeout(_this.s.deselectTimeout);
  410. _this._updateSelection(!_this.s.updating);
  411. _this.dom.clear.removeClass(_this.classes.disabledButton).removeAttr('disabled');
  412. });
  413. // When an item is deselected on the pane, re add the currently selected items to the array
  414. // which holds selected items. Custom search will be performed.
  415. this.s.dtPane.off('deselect.dtsp').on('deselect.dtsp', function () {
  416. _this.s.deselectTimeout = setTimeout(function () {
  417. _this._updateSelection(true);
  418. if (_this.s.dtPane.rows({ selected: true }).data().toArray().length === 0) {
  419. _this.dom.clear.addClass(_this.classes.disabledButton).attr('disabled', 'true');
  420. }
  421. }, 50);
  422. });
  423. // If we attempty to turn off this event then it will ruin behaviour in other panes
  424. // so need to make sure that it is only done once
  425. if (this.s.firstSet) {
  426. this.s.firstSet = false;
  427. // When saving the state store all of the selected rows for preselection next time around
  428. this.s.dt.on('stateSaveParams.dtsp', function (e, settings, data) {
  429. // If the data being passed in is empty then state clear must have occured
  430. // so clear the panes state as well
  431. if ($$4.isEmptyObject(data)) {
  432. _this.s.dtPane.state.clear();
  433. return;
  434. }
  435. var bins;
  436. var order;
  437. var selected = [];
  438. var collapsed;
  439. var searchTerm;
  440. var arrayFilter;
  441. // Get all of the data needed for the state save from the pane
  442. if (_this.s.dtPane) {
  443. selected = _this.s.dtPane
  444. .rows({ selected: true })
  445. .data()
  446. .map(function (item) { return item.filter.toString(); })
  447. .toArray();
  448. searchTerm = _this.dom.searchBox.val();
  449. order = _this.s.dtPane.order();
  450. bins = _this.s.rowData.binsOriginal;
  451. arrayFilter = _this.s.rowData.arrayOriginal;
  452. collapsed = _this.dom.collapseButton.hasClass(_this.classes.rotated);
  453. }
  454. if (data.searchPanes === undefined) {
  455. data.searchPanes = {};
  456. }
  457. if (data.searchPanes.panes === undefined) {
  458. data.searchPanes.panes = [];
  459. }
  460. for (var i = 0; i < data.searchPanes.panes.length; i++) {
  461. if (data.searchPanes.panes[i].id === _this.s.index) {
  462. data.searchPanes.panes.splice(i, 1);
  463. i--;
  464. }
  465. }
  466. // Add the panes data to the state object
  467. data.searchPanes.panes.push({
  468. arrayFilter: arrayFilter,
  469. bins: bins,
  470. collapsed: collapsed,
  471. id: _this.s.index,
  472. order: order,
  473. searchTerm: searchTerm,
  474. selected: selected
  475. });
  476. });
  477. }
  478. this.s.dtPane.off('user-select.dtsp').on('user-select.dtsp', function (e, _dt, type, cell, originalEvent) {
  479. originalEvent.stopPropagation();
  480. });
  481. this.s.dtPane.off('draw.dtsp').on('draw.dtsp', function () { return _this.adjustTopRow(); });
  482. // When the button to order by the name of the options is clicked then
  483. // change the ordering to whatever it isn't currently
  484. this.dom.nameButton.off('click.dtsp').on('click.dtsp', function () {
  485. var currentOrder = _this.s.dtPane.order()[0][1];
  486. _this.s.dtPane.order([0, currentOrder === 'asc' ? 'desc' : 'asc']).draw();
  487. // This state save is required so that the ordering of the panes is maintained
  488. _this.s.dt.state.save();
  489. });
  490. // When the button to order by the number of entries in the column is clicked then
  491. // change the ordering to whatever it isn't currently
  492. this.dom.countButton.off('click.dtsp').on('click.dtsp', function () {
  493. var currentOrder = _this.s.dtPane.order()[0][1];
  494. _this.s.dtPane.order([1, currentOrder === 'asc' ? 'desc' : 'asc']).draw();
  495. // This state save is required so that the ordering of the panes is maintained
  496. _this.s.dt.state.save();
  497. });
  498. // When the button to order by the number of entries in the column is clicked then
  499. // change the ordering to whatever it isn't currently
  500. this.dom.collapseButton.off('click.dtsp').on('click.dtsp', function (e) {
  501. e.stopPropagation();
  502. var container = $$4(_this.s.dtPane.table().container());
  503. // Toggle the classes
  504. container.toggleClass(_this.classes.hidden);
  505. _this.dom.topRow.toggleClass(_this.classes.bordered);
  506. _this.dom.nameButton.toggleClass(_this.classes.disabledButton);
  507. _this.dom.countButton.toggleClass(_this.classes.disabledButton);
  508. _this.dom.searchButton.toggleClass(_this.classes.disabledButton);
  509. _this.dom.collapseButton.toggleClass(_this.classes.rotated);
  510. if (container.hasClass(_this.classes.hidden)) {
  511. _this.dom.topRow.on('click.dtsp', function () { return _this.dom.collapseButton.click(); });
  512. }
  513. else {
  514. _this.dom.topRow.off('click.dtsp');
  515. }
  516. _this.s.dt.state.save();
  517. });
  518. // When the clear button is clicked reset the pane
  519. this.dom.clear.off('click.dtsp').on('click.dtsp', function () {
  520. var searches = _this.dom.container.find('.' + _this.classes.search.replace(/ /g, '.'));
  521. searches.each(function () {
  522. // set the value of the search box to be an empty string and then search on that, effectively reseting
  523. $$4(this).val('').trigger('input');
  524. });
  525. _this.clearPane();
  526. });
  527. // When the search button is clicked then draw focus to the search box
  528. this.dom.searchButton.off('click.dtsp').on('click.dtsp', function () { return _this.dom.searchBox.focus(); });
  529. // When a character is inputted into the searchbox search the pane for matching values.
  530. // Doing it this way means that no button has to be clicked to trigger a search, it is done asynchronously
  531. this.dom.searchBox.off('click.dtsp').on('input.dtsp', function () {
  532. var searchval = _this.dom.searchBox.val();
  533. _this.s.dtPane.search(searchval).draw();
  534. if (typeof searchval === 'string' &&
  535. (searchval.length > 0 ||
  536. searchval.length === 0 && _this.s.dtPane.rows({ selected: true }).data().toArray().length > 0)) {
  537. _this.dom.clear.removeClass(_this.classes.disabledButton).removeAttr('disabled');
  538. }
  539. else {
  540. _this.dom.clear.addClass(_this.classes.disabledButton).attr('disabled', 'true');
  541. }
  542. // This state save is required so that the searching on the panes is maintained
  543. _this.s.dt.state.save();
  544. });
  545. // WORKAROUND
  546. // If this line is removed, the select listeners aren't present on
  547. // the panes for some reason when a rebuild occurs
  548. this.s.dtPane.select.style(this.s.colOpts.dtOpts && this.s.colOpts.dtOpts.select && this.s.colOpts.dtOpts.select.style
  549. ? this.s.colOpts.dtOpts.select.style
  550. : this.c.dtOpts && this.c.dtOpts.select && this.c.dtOpts.select.style
  551. ? this.c.dtOpts.select.style
  552. : 'os');
  553. };
  554. /**
  555. * Populates the SearchPane based off of the data that has been recieved from the server
  556. *
  557. * This method is overriden by SearchPaneST
  558. *
  559. * @param dataIn The data that has been sent from the server
  560. */
  561. SearchPane.prototype._serverPopulate = function (dataIn) {
  562. if (dataIn.tableLength) {
  563. this.s.tableLength = dataIn.tableLength;
  564. this.s.rowData.totalOptions = this.s.tableLength;
  565. }
  566. else if (this.s.tableLength === null || this.s.dt.rows()[0].length > this.s.tableLength) {
  567. this.s.tableLength = this.s.dt.rows()[0].length;
  568. this.s.rowData.totalOptions = this.s.tableLength;
  569. }
  570. var colTitle = this.s.dt.column(this.s.index).dataSrc();
  571. // If there is SP data for this column add it to the data array and bin
  572. if (dataIn.searchPanes.options[colTitle]) {
  573. for (var _i = 0, _a = dataIn.searchPanes.options[colTitle]; _i < _a.length; _i++) {
  574. var dataPoint = _a[_i];
  575. this.s.rowData.arrayFilter.push({
  576. display: dataPoint.label,
  577. filter: dataPoint.value,
  578. sort: dataPoint.label,
  579. type: dataPoint.label
  580. });
  581. this.s.rowData.bins[dataPoint.value] = dataPoint.total;
  582. }
  583. }
  584. var binLength = Object.keys(this.s.rowData.bins).length;
  585. var uniqueRatio = this._uniqueRatio(binLength, this.s.tableLength);
  586. // Don't show the pane if there isnt enough variance in the data, or there is only 1 entry for that pane
  587. if (this.s.displayed === false &&
  588. ((this.s.colOpts.show === undefined && this.s.colOpts.threshold === null ?
  589. uniqueRatio > this.c.threshold :
  590. uniqueRatio > this.s.colOpts.threshold) ||
  591. this.s.colOpts.show !== true && binLength <= 1)) {
  592. this.dom.container.addClass(this.classes.hidden);
  593. this.s.displayed = false;
  594. return;
  595. }
  596. // Store the original data
  597. this.s.rowData.arrayOriginal = this.s.rowData.arrayFilter;
  598. this.s.rowData.binsOriginal = this.s.rowData.bins;
  599. // Flag this pane as being displayed
  600. this.s.displayed = true;
  601. };
  602. /**
  603. * Expands the pane from the collapsed state
  604. */
  605. SearchPane.prototype.show = function () {
  606. if (!this.s.displayed) {
  607. return;
  608. }
  609. this.dom.topRow.removeClass(this.classes.bordered);
  610. this.dom.nameButton.removeClass(this.classes.disabledButton);
  611. this.dom.countButton.removeClass(this.classes.disabledButton);
  612. this.dom.searchButton.removeClass(this.classes.disabledButton);
  613. this.dom.collapseButton.removeClass(this.classes.rotated);
  614. $$4(this.s.dtPane.table().container()).removeClass(this.classes.hidden);
  615. };
  616. /**
  617. * Finds the ratio of the number of different options in the table to the number of rows
  618. *
  619. * @param bins the number of different options in the table
  620. * @param rowCount the total number of rows in the table
  621. * @returns {number} returns the ratio
  622. */
  623. SearchPane.prototype._uniqueRatio = function (bins, rowCount) {
  624. if (rowCount > 0 &&
  625. (this.s.rowData.totalOptions > 0 && !this.s.dt.page.info().serverSide ||
  626. this.s.dt.page.info().serverSide && this.s.tableLength > 0)) {
  627. return bins / this.s.rowData.totalOptions;
  628. }
  629. return 1;
  630. };
  631. /**
  632. * Updates the panes if one of the options to do so has been set to true
  633. * rather than the filtered message when using viewTotal.
  634. */
  635. SearchPane.prototype.updateTable = function () {
  636. var selectedRows = this.s.dtPane.rows({ selected: true }).data().toArray().map(function (el) { return el.filter; });
  637. this.s.selections = selectedRows;
  638. this._searchExtras();
  639. };
  640. /**
  641. * Adds the custom options to the pane
  642. *
  643. * @returns {Array} Returns the array of rows which have been added to the pane
  644. */
  645. SearchPane.prototype._getComparisonRows = function () {
  646. // Find the appropriate options depending on whether this is a pane for a specific column or a custom pane
  647. var options = this.s.colOpts.options
  648. ? this.s.colOpts.options
  649. : this.s.customPaneSettings && this.s.customPaneSettings.options
  650. ? this.s.customPaneSettings.options
  651. : undefined;
  652. if (options === undefined) {
  653. return;
  654. }
  655. var allRows = this.s.dt.rows();
  656. var tableValsTotal = allRows.data().toArray();
  657. var rows = [];
  658. // Clear all of the other rows from the pane, only custom options are to be displayed when they are defined
  659. this.s.dtPane.clear();
  660. this.s.indexes = [];
  661. for (var _i = 0, options_1 = options; _i < options_1.length; _i++) {
  662. var comp = options_1[_i];
  663. // Initialise the object which is to be placed in the row
  664. var insert = comp.label !== '' ?
  665. comp.label :
  666. this.emptyMessage();
  667. var comparisonObj = {
  668. className: comp.className,
  669. display: insert,
  670. filter: typeof comp.value === 'function' ? comp.value : [],
  671. sort: insert,
  672. total: 0,
  673. type: insert
  674. };
  675. // If a custom function is in place
  676. if (typeof comp.value === 'function') {
  677. // Count the number of times the function evaluates to true for the original data in the Table
  678. for (var i = 0; i < tableValsTotal.length; i++) {
  679. if (comp.value.call(this.s.dt, tableValsTotal[i], allRows[0][i])) {
  680. comparisonObj.total++;
  681. }
  682. }
  683. // Update the comparisonObj
  684. if (typeof comparisonObj.filter !== 'function') {
  685. comparisonObj.filter.push(comp.filter);
  686. }
  687. }
  688. rows.push(this.addRow(comparisonObj.display, comparisonObj.filter, comparisonObj.sort, comparisonObj.type, comparisonObj.className, comparisonObj.total));
  689. }
  690. return rows;
  691. };
  692. SearchPane.prototype._getMessage = function (row) {
  693. return this.s.dt.i18n('searchPanes.count', this.c.i18n.count).replace(/{total}/g, row.total);
  694. };
  695. /**
  696. * Overridden in SearchPaneViewTotal and SearchPaneCascade to get the number of times a specific value is shown
  697. *
  698. * Here it is blanked so that it takes no action
  699. *
  700. * @param filter The filter value
  701. * @returns undefined
  702. */
  703. // eslint-disable-next-line @typescript-eslint/no-unused-vars
  704. SearchPane.prototype._getShown = function (filter) {
  705. return undefined;
  706. };
  707. /**
  708. * Get's the pane config appropriate to this class
  709. *
  710. * @returns The config needed to create a pane of this type
  711. */
  712. SearchPane.prototype._getPaneConfig = function () {
  713. var _this = this;
  714. // eslint-disable-next-line no-extra-parens
  715. var haveScroller = dataTable$1.Scroller;
  716. var langOpts = this.s.dt.settings()[0].oLanguage;
  717. langOpts.url = undefined;
  718. langOpts.sUrl = undefined;
  719. return {
  720. columnDefs: [
  721. {
  722. className: 'dtsp-nameColumn',
  723. data: 'display',
  724. render: function (data, type, row) {
  725. if (type === 'sort') {
  726. return row.sort;
  727. }
  728. else if (type === 'type') {
  729. return row.type;
  730. }
  731. var message = _this._getMessage(row);
  732. // We are displaying the count in the same columne as the name of the search option.
  733. // This is so that there is not need to call columns.adjust()
  734. // which in turn speeds up the code
  735. var pill = '<span class="' + _this.classes.pill + '">' + message + '</span>';
  736. if (!_this.c.viewCount || !_this.s.colOpts.viewCount) {
  737. pill = '';
  738. }
  739. if (type === 'filter') {
  740. return typeof data === 'string' && data.match(/<[^>]*>/) !== null ?
  741. data.replace(/<[^>]*>/g, '') :
  742. data;
  743. }
  744. return '<div class="' + _this.classes.nameCont + '"><span title="' +
  745. (typeof data === 'string' && data.match(/<[^>]*>/) !== null ?
  746. data.replace(/<[^>]*>/g, '') :
  747. data) +
  748. '" class="' + _this.classes.name + '">' +
  749. data + '</span>' +
  750. pill + '</div>';
  751. },
  752. targets: 0,
  753. // Accessing the private datatables property to set type based on the original table.
  754. // This is null if not defined by the user, meaning that automatic type detection
  755. // would take place
  756. type: this.s.dt.settings()[0].aoColumns[this.s.index] ?
  757. this.s.dt.settings()[0].aoColumns[this.s.index]._sManualType :
  758. null
  759. },
  760. {
  761. className: 'dtsp-countColumn ' + this.classes.badgePill,
  762. data: 'total',
  763. searchable: false,
  764. targets: 1,
  765. visible: false
  766. }
  767. ],
  768. deferRender: true,
  769. dom: 't',
  770. info: false,
  771. language: langOpts,
  772. paging: haveScroller ? true : false,
  773. scrollX: false,
  774. scrollY: '200px',
  775. scroller: haveScroller ? true : false,
  776. select: true,
  777. stateSave: this.s.dt.settings()[0].oFeatures.bStateSave ? true : false
  778. };
  779. };
  780. /**
  781. * This method allows for changes to the panes and table to be made when a selection or a deselection occurs
  782. */
  783. SearchPane.prototype._makeSelection = function () {
  784. this.updateTable();
  785. this.s.updating = true;
  786. this.s.dt.draw();
  787. this.s.updating = false;
  788. };
  789. /**
  790. * Populates an array with all of the data for the table
  791. *
  792. * @param rowIdx The current row index to be compared
  793. * @param arrayFilter The array that is to be populated with row Details
  794. * @param settings The DataTable settings object
  795. * @param bins The bins object that is to be populated with the row counts
  796. */
  797. SearchPane.prototype._populatePaneArray = function (rowIdx, arrayFilter, settings, bins) {
  798. if (bins === void 0) { bins = this.s.rowData.bins; }
  799. // Retrieve the rendered data from the cell using the fnGetCellData function
  800. // rather than the cell().render API method for optimisation
  801. if (typeof this.s.colOpts.orthogonal === 'string') {
  802. var rendered = settings.oApi._fnGetCellData(settings, rowIdx, this.s.index, this.s.colOpts.orthogonal);
  803. this.s.rowData.filterMap.set(rowIdx, rendered);
  804. this._addOption(rendered, rendered, rendered, rendered, arrayFilter, bins);
  805. this.s.rowData.totalOptions++;
  806. }
  807. else {
  808. var filter = settings.oApi._fnGetCellData(settings, rowIdx, this.s.index, this.s.colOpts.orthogonal.search);
  809. // Null and empty string are to be considered the same value
  810. if (filter === null) {
  811. filter = '';
  812. }
  813. if (typeof filter === 'string') {
  814. filter = filter.replace(/<[^>]*>/g, '');
  815. }
  816. this.s.rowData.filterMap.set(rowIdx, filter);
  817. if (!bins[filter]) {
  818. bins[filter] = 1;
  819. this._addOption(filter, settings.oApi._fnGetCellData(settings, rowIdx, this.s.index, this.s.colOpts.orthogonal.display), settings.oApi._fnGetCellData(settings, rowIdx, this.s.index, this.s.colOpts.orthogonal.sort), settings.oApi._fnGetCellData(settings, rowIdx, this.s.index, this.s.colOpts.orthogonal.type), arrayFilter, bins);
  820. this.s.rowData.totalOptions++;
  821. }
  822. else {
  823. bins[filter]++;
  824. this.s.rowData.totalOptions++;
  825. }
  826. }
  827. };
  828. /**
  829. * Reloads all of the previous selects into the panes
  830. *
  831. * @param loadedFilter The loaded filters from a previous state
  832. */
  833. SearchPane.prototype._reloadSelect = function (loadedFilter) {
  834. // If the state was not saved don't selected any
  835. if (loadedFilter === undefined) {
  836. return;
  837. }
  838. var idx;
  839. // For each pane, check that the loadedFilter list exists and is not null,
  840. // find the id of each search item and set it to be selected.
  841. for (var i = 0; i < loadedFilter.searchPanes.panes.length; i++) {
  842. if (loadedFilter.searchPanes.panes[i].id === this.s.index) {
  843. idx = i;
  844. break;
  845. }
  846. }
  847. if (idx) {
  848. var table = this.s.dtPane;
  849. var rows = table.rows({ order: 'index' }).data().map(function (item) { return item.filter !== null ?
  850. item.filter.toString() :
  851. null; }).toArray();
  852. for (var _i = 0, _a = loadedFilter.searchPanes.panes[idx].selected; _i < _a.length; _i++) {
  853. var filter = _a[_i];
  854. var id = -1;
  855. if (filter !== null) {
  856. id = rows.indexOf(filter.toString());
  857. }
  858. if (id > -1) {
  859. this.s.serverSelecting = true;
  860. table.row(id).select();
  861. this.s.serverSelecting = false;
  862. }
  863. }
  864. }
  865. };
  866. /**
  867. * Notes the rows that have been selected within this pane and stores them internally
  868. *
  869. * @param notUpdating Whether the panes are updating themselves or not
  870. */
  871. SearchPane.prototype._updateSelection = function (notUpdating) {
  872. this.s.scrollTop = $$4(this.s.dtPane.table().node()).parent()[0].scrollTop;
  873. if (this.s.dt.page.info().serverSide && !this.s.updating) {
  874. if (!this.s.serverSelecting) {
  875. this.s.serverSelect = this.s.dtPane.rows({ selected: true }).data().toArray();
  876. this.s.dt.draw(false);
  877. }
  878. }
  879. else if (notUpdating) {
  880. this._makeSelection();
  881. }
  882. };
  883. /**
  884. * Takes in potentially undetected rows and adds them to the array if they are not yet featured
  885. *
  886. * @param filter the filter value of the potential row
  887. * @param display the display value of the potential row
  888. * @param sort the sort value of the potential row
  889. * @param type the type value of the potential row
  890. * @param arrayFilter the array to be populated
  891. * @param bins the bins to be populated
  892. */
  893. SearchPane.prototype._addOption = function (filter, display, sort, type, arrayFilter, bins) {
  894. // If the filter is an array then take a note of this, and add the elements to the arrayFilter array
  895. if (Array.isArray(filter) || filter instanceof dataTable$1.Api) {
  896. // Convert to an array so that we can work with it
  897. if (filter instanceof dataTable$1.Api) {
  898. filter = filter.toArray();
  899. display = display.toArray();
  900. }
  901. if (filter.length === display.length) {
  902. for (var i = 0; i < filter.length; i++) {
  903. // If we haven't seen this row before add it
  904. if (!bins[filter[i]]) {
  905. bins[filter[i]] = 1;
  906. arrayFilter.push({
  907. display: display[i],
  908. filter: filter[i],
  909. sort: sort[i],
  910. type: type[i]
  911. });
  912. }
  913. // Otherwise just increment the count
  914. else {
  915. bins[filter[i]]++;
  916. }
  917. this.s.rowData.totalOptions++;
  918. }
  919. return;
  920. }
  921. throw new Error('display and filter not the same length');
  922. }
  923. // If the values were affected by othogonal data and are not an array then check if it is already present
  924. else if (typeof this.s.colOpts.orthogonal === 'string') {
  925. if (!bins[filter]) {
  926. bins[filter] = 1;
  927. arrayFilter.push({
  928. display: display,
  929. filter: filter,
  930. sort: sort,
  931. type: type
  932. });
  933. this.s.rowData.totalOptions++;
  934. }
  935. else {
  936. bins[filter]++;
  937. this.s.rowData.totalOptions++;
  938. }
  939. }
  940. // Otherwise we must just be adding an option
  941. else {
  942. arrayFilter.push({
  943. display: display,
  944. filter: filter,
  945. sort: sort,
  946. type: type
  947. });
  948. }
  949. };
  950. /**
  951. * Method to construct the actual pane.
  952. *
  953. * @param selectedRows previously selected Rows to be reselected
  954. * @param dataIn Data that should be used to populate this pane
  955. * @param prevEl Reference to the previous element, used to ensure insert is in the correct location
  956. * @returns boolean to indicate whether this pane was the last one to have a selection made
  957. */
  958. SearchPane.prototype._buildPane = function (selectedRows, dataIn, prevEl) {
  959. var _this = this;
  960. if (selectedRows === void 0) { selectedRows = []; }
  961. if (dataIn === void 0) { dataIn = null; }
  962. if (prevEl === void 0) { prevEl = null; }
  963. // Aliases
  964. this.s.selections = [];
  965. // Other Variables
  966. var loadedFilter = this.s.dt.state.loaded();
  967. // If the listeners have not been set yet then using the latest state may result in funny errors
  968. if (this.s.listSet) {
  969. loadedFilter = this.s.dt.state();
  970. }
  971. // If it is not a custom pane in place
  972. if (this.s.colExists) {
  973. var idx = -1;
  974. if (loadedFilter && loadedFilter.searchPanes && loadedFilter.searchPanes.panes) {
  975. for (var i = 0; i < loadedFilter.searchPanes.panes.length; i++) {
  976. if (loadedFilter.searchPanes.panes[i].id === this.s.index) {
  977. idx = i;
  978. break;
  979. }
  980. }
  981. }
  982. // Perform checks that do not require populate pane to run
  983. if ((this.s.colOpts.show === false ||
  984. this.s.colOpts.show !== undefined && this.s.colOpts.show !== true) &&
  985. idx === -1) {
  986. this.dom.container.addClass(this.classes.hidden);
  987. this.s.displayed = false;
  988. return false;
  989. }
  990. else if (this.s.colOpts.show === true || idx !== -1) {
  991. this.s.displayed = true;
  992. }
  993. if (!this.s.dt.page.info().serverSide &&
  994. (!dataIn ||
  995. !dataIn.searchPanes ||
  996. !dataIn.searchPanes.options)) {
  997. // Only run populatePane if the data has not been collected yet
  998. if (this.s.rowData.arrayFilter.length === 0) {
  999. this.s.rowData.totalOptions = 0;
  1000. this._populatePane();
  1001. this.s.rowData.arrayOriginal = this.s.rowData.arrayFilter;
  1002. this.s.rowData.binsOriginal = this.s.rowData.bins;
  1003. }
  1004. var binLength = Object.keys(this.s.rowData.binsOriginal).length;
  1005. var uniqueRatio = this._uniqueRatio(binLength, this.s.dt.rows()[0].length);
  1006. // Don't show the pane if there isn't enough variance in the data, or there is only 1 entry
  1007. // for that pane
  1008. if (this.s.displayed === false &&
  1009. ((this.s.colOpts.show === undefined && this.s.colOpts.threshold === null ?
  1010. uniqueRatio > this.c.threshold :
  1011. uniqueRatio > this.s.colOpts.threshold) ||
  1012. this.s.colOpts.show !== true && binLength <= 1)) {
  1013. this.dom.container.addClass(this.classes.hidden);
  1014. this.s.displayed = false;
  1015. return;
  1016. }
  1017. this.dom.container.addClass(this.classes.show);
  1018. this.s.displayed = true;
  1019. }
  1020. else if (dataIn && dataIn.searchPanes && dataIn.searchPanes.options) {
  1021. this._serverPopulate(dataIn);
  1022. }
  1023. }
  1024. else {
  1025. this.s.displayed = true;
  1026. }
  1027. // If the variance is accceptable then display the search pane
  1028. this._displayPane();
  1029. if (!this.s.listSet) {
  1030. // Here, when the state is loaded if the data object on the original table is empty,
  1031. // then a state.clear() must have occurred, so delete all of the panes tables state objects too.
  1032. this.dom.dtP.on('stateLoadParams.dtsp', function (e, settings, data) {
  1033. if ($$4.isEmptyObject(_this.s.dt.state.loaded())) {
  1034. $$4.each(data, function (index) {
  1035. delete data[index];
  1036. });
  1037. }
  1038. });
  1039. }
  1040. // Add the container to the document in its original location
  1041. if (prevEl !== null && this.dom.panesContainer.has(prevEl).length > 0) {
  1042. this.dom.container.insertAfter(prevEl);
  1043. }
  1044. else {
  1045. this.dom.panesContainer.prepend(this.dom.container);
  1046. }
  1047. // Declare the datatable for the pane
  1048. var errMode = $$4.fn.dataTable.ext.errMode;
  1049. $$4.fn.dataTable.ext.errMode = 'none';
  1050. // eslint-disable-next-line no-extra-parens
  1051. this.s.dtPane = this.dom.dtP.DataTable($$4.extend(true, this._getPaneConfig(), this.c.dtOpts, this.s.colOpts ? this.s.colOpts.dtOpts : {}, this.s.colOpts.options || !this.s.colExists ?
  1052. {
  1053. createdRow: function (row, data) {
  1054. $$4(row).addClass(data.className);
  1055. }
  1056. } :
  1057. undefined, this.s.customPaneSettings !== null && this.s.customPaneSettings.dtOpts ?
  1058. this.s.customPaneSettings.dtOpts :
  1059. {}, $$4.fn.dataTable.versionCheck('2')
  1060. ? {
  1061. layout: {
  1062. bottomLeft: null,
  1063. bottomRight: null,
  1064. topLeft: null,
  1065. topRight: null
  1066. }
  1067. }
  1068. : {}));
  1069. this.dom.dtP.addClass(this.classes.table);
  1070. // Getting column titles is a little messy
  1071. var headerText = 'Custom Pane';
  1072. if (this.s.customPaneSettings && this.s.customPaneSettings.header) {
  1073. headerText = this.s.customPaneSettings.header;
  1074. }
  1075. else if (this.s.colOpts.header) {
  1076. headerText = this.s.colOpts.header;
  1077. }
  1078. else if (this.s.colExists) {
  1079. headerText = $$4.fn.dataTable.versionCheck('2')
  1080. ? this.s.dt.column(this.s.index).title()
  1081. : this.s.dt.settings()[0].aoColumns[this.s.index].sTitle;
  1082. }
  1083. headerText = this._escapeHTML(headerText);
  1084. this.dom.searchBox.attr('placeholder', headerText);
  1085. // As the pane table is not in the document yet we must initialise select ourselves
  1086. // eslint-disable-next-line no-extra-parens
  1087. $$4.fn.dataTable.select.init(this.s.dtPane);
  1088. $$4.fn.dataTable.ext.errMode = errMode;
  1089. // If it is not a custom pane
  1090. if (this.s.colExists) {
  1091. // Add all of the search options to the pane
  1092. for (var i = 0, ien = this.s.rowData.arrayFilter.length; i < ien; i++) {
  1093. if (this.s.dt.page.info().serverSide) {
  1094. var row = this.addRow(this.s.rowData.arrayFilter[i].display, this.s.rowData.arrayFilter[i].filter, this.s.rowData.arrayFilter[i].sort, this.s.rowData.arrayFilter[i].type);
  1095. for (var _i = 0, _a = this.s.serverSelect; _i < _a.length; _i++) {
  1096. var option = _a[_i];
  1097. if (option.filter === this.s.rowData.arrayFilter[i].filter) {
  1098. this.s.serverSelecting = true;
  1099. row.select();
  1100. this.s.serverSelecting = false;
  1101. }
  1102. }
  1103. }
  1104. else if (!this.s.dt.page.info().serverSide && this.s.rowData.arrayFilter[i]) {
  1105. this.addRow(this.s.rowData.arrayFilter[i].display, this.s.rowData.arrayFilter[i].filter, this.s.rowData.arrayFilter[i].sort, this.s.rowData.arrayFilter[i].type);
  1106. }
  1107. else if (!this.s.dt.page.info().serverSide) {
  1108. // Just pass an empty string as the message will be calculated based on that in addRow()
  1109. this.addRow('', '', '', '');
  1110. }
  1111. }
  1112. }
  1113. // eslint-disable-next-line no-extra-parens
  1114. dataTable$1.select.init(this.s.dtPane);
  1115. // If there are custom options set or it is a custom pane then get them
  1116. if (this.s.colOpts.options ||
  1117. this.s.customPaneSettings && this.s.customPaneSettings.options) {
  1118. this._getComparisonRows();
  1119. }
  1120. // Display the pane
  1121. this.s.dtPane.draw();
  1122. this.s.dtPane.table().node().parentNode.scrollTop = this.s.scrollTop;
  1123. this.adjustTopRow();
  1124. this.setListeners();
  1125. this.s.listSet = true;
  1126. for (var _b = 0, selectedRows_1 = selectedRows; _b < selectedRows_1.length; _b++) {
  1127. var selection = selectedRows_1[_b];
  1128. if (selection) {
  1129. for (var _c = 0, _d = this.s.dtPane.rows().indexes().toArray(); _c < _d.length; _c++) {
  1130. var row = _d[_c];
  1131. if (this.s.dtPane.row(row).data() &&
  1132. selection.filter === this.s.dtPane.row(row).data().filter) {
  1133. // If this is happening when serverSide processing is happening then
  1134. // different behaviour is needed
  1135. if (this.s.dt.page.info().serverSide) {
  1136. this.s.serverSelecting = true;
  1137. this.s.dtPane.row(row).select();
  1138. this.s.serverSelecting = false;
  1139. }
  1140. else {
  1141. this.s.dtPane.row(row).select();
  1142. }
  1143. }
  1144. }
  1145. }
  1146. }
  1147. // If SSP and the table is ready, apply the search for the pane
  1148. if (this.s.dt.page.info().serverSide) {
  1149. this.s.dtPane.search(this.dom.searchBox.val()).draw();
  1150. }
  1151. if ((this.c.initCollapsed && this.s.colOpts.initCollapsed !== false ||
  1152. this.s.colOpts.initCollapsed) &&
  1153. (this.c.collapse && this.s.colOpts.collapse !== false ||
  1154. this.s.colOpts.collapse)) {
  1155. // If the pane has not initialised yet then we need to wait for it to do so before collapsing
  1156. // Otherwise the container that the class is added to does not exist
  1157. if (this.s.dtPane.settings()[0]._bInitComplete) {
  1158. this.collapse();
  1159. }
  1160. else {
  1161. this.s.dtPane.one('init', function () { return _this.collapse(); });
  1162. }
  1163. }
  1164. // Reload the selection, searchbox entry and ordering from the previous state
  1165. // Need to check here if SSP that this is the first draw, otherwise it will infinite loop
  1166. if (loadedFilter &&
  1167. loadedFilter.searchPanes &&
  1168. loadedFilter.searchPanes.panes &&
  1169. (!dataIn ||
  1170. dataIn.draw === 1)) {
  1171. this._reloadSelect(loadedFilter);
  1172. for (var _e = 0, _f = loadedFilter.searchPanes.panes; _e < _f.length; _e++) {
  1173. var pane = _f[_e];
  1174. if (pane.id === this.s.index) {
  1175. // Save some time by only triggering an input if there is a value
  1176. if (pane.searchTerm && pane.searchTerm.length > 0) {
  1177. this.dom.searchBox.val(pane.searchTerm).trigger('input');
  1178. }
  1179. if (pane.order) {
  1180. this.s.dtPane.order(pane.order).draw();
  1181. }
  1182. // Is the pane to be hidden or shown?
  1183. if (pane.collapsed) {
  1184. this.collapse();
  1185. }
  1186. else {
  1187. this.show();
  1188. }
  1189. }
  1190. }
  1191. }
  1192. return true;
  1193. };
  1194. /**
  1195. * Appends all of the HTML elements to their relevant parent Elements
  1196. */
  1197. SearchPane.prototype._displayPane = function () {
  1198. // Empty everything to start again
  1199. this.dom.dtP.empty();
  1200. this.dom.topRow.empty().addClass(this.classes.topRow);
  1201. // If there are more than 3 columns defined then make there be a smaller gap between the panes
  1202. if (parseInt(this.c.layout.split('-')[1], 10) > 3) {
  1203. this.dom.container.addClass(this.classes.smallGap);
  1204. }
  1205. this.dom.topRow
  1206. .addClass(this.classes.subRowsContainer)
  1207. .append(this.dom.upper.append(this.dom.searchCont))
  1208. .append(this.dom.lower.append(this.dom.buttonGroup));
  1209. // If no selections have been made in the pane then disable the clear button
  1210. if (this.c.dtOpts.searching === false ||
  1211. this.s.colOpts.dtOpts && this.s.colOpts.dtOpts.searching === false ||
  1212. (!this.c.controls || !this.s.colOpts.controls) ||
  1213. this.s.customPaneSettings &&
  1214. this.s.customPaneSettings.dtOpts &&
  1215. this.s.customPaneSettings.dtOpts.searching !== undefined &&
  1216. !this.s.customPaneSettings.dtOpts.searching) {
  1217. this.dom.searchBox
  1218. .removeClass(this.classes.paneInputButton)
  1219. .addClass(this.classes.disabledButton)
  1220. .attr('disabled', 'true');
  1221. }
  1222. this.dom.searchBox.appendTo(this.dom.searchCont);
  1223. // Create the contents of the searchCont div. Worth noting that this function will change when using semantic ui
  1224. this._searchContSetup();
  1225. // If the clear button is allowed to show then display it
  1226. if (this.c.clear && this.c.controls && this.s.colOpts.controls) {
  1227. this.dom.clear.appendTo(this.dom.buttonGroup);
  1228. }
  1229. if (this.c.orderable && this.s.colOpts.orderable && this.c.controls && this.s.colOpts.controls) {
  1230. this.dom.nameButton.appendTo(this.dom.buttonGroup);
  1231. }
  1232. // If the count column is hidden then don't display the ordering button for it
  1233. if (this.c.viewCount &&
  1234. this.s.colOpts.viewCount &&
  1235. this.c.orderable &&
  1236. this.s.colOpts.orderable &&
  1237. this.c.controls &&
  1238. this.s.colOpts.controls) {
  1239. this.dom.countButton.appendTo(this.dom.buttonGroup);
  1240. }
  1241. if ((this.c.collapse && this.s.colOpts.collapse !== false ||
  1242. this.s.colOpts.collapse) &&
  1243. this.c.controls && this.s.colOpts.controls) {
  1244. this.dom.collapseButton.appendTo(this.dom.buttonGroup);
  1245. }
  1246. this.dom.container.prepend(this.dom.topRow).append(this.dom.dtP).show();
  1247. };
  1248. /**
  1249. * Escape html characters within a string
  1250. *
  1251. * @param txt the string to be escaped
  1252. * @returns the escaped string
  1253. */
  1254. SearchPane.prototype._escapeHTML = function (txt) {
  1255. return txt
  1256. .toString()
  1257. .replace(/&amp;/g, '&')
  1258. .replace(/&lt;/g, '<')
  1259. .replace(/&gt;/g, '>')
  1260. .replace(/&quot;/g, '"');
  1261. };
  1262. /**
  1263. * Gets the options for the row for the customPanes
  1264. *
  1265. * @returns {object} The options for the row extended to include the options from the user.
  1266. */
  1267. SearchPane.prototype._getBonusOptions = function () {
  1268. // We need to reset the thresholds as if they have a value in colOpts then that value will be used
  1269. var defaultMutator = {
  1270. threshold: null
  1271. };
  1272. return $$4.extend(true, {}, SearchPane.defaults, defaultMutator, this.c ? this.c : {});
  1273. };
  1274. /**
  1275. * Gets the options for the row for the customPanes
  1276. *
  1277. * @returns {object} The options for the row extended to include the options from the user.
  1278. */
  1279. SearchPane.prototype._getOptions = function () {
  1280. var table = this.s.dt;
  1281. // We need to reset the thresholds as if they have a value in colOpts then that value will be used
  1282. var defaultMutator = {
  1283. collapse: null,
  1284. emptyMessage: false,
  1285. initCollapsed: null,
  1286. threshold: null
  1287. };
  1288. var columnOptions = table.settings()[0].aoColumns[this.s.index].searchPanes;
  1289. var colOpts = $$4.extend(true, {}, SearchPane.defaults, defaultMutator, columnOptions);
  1290. if (columnOptions && columnOptions.hideCount && columnOptions.viewCount === undefined) {
  1291. colOpts.viewCount = !columnOptions.hideCount;
  1292. }
  1293. return colOpts;
  1294. };
  1295. /**
  1296. * Fill the array with the values that are currently being displayed in the table
  1297. */
  1298. SearchPane.prototype._populatePane = function () {
  1299. this.s.rowData.arrayFilter = [];
  1300. this.s.rowData.bins = {};
  1301. var settings = this.s.dt.settings()[0];
  1302. if (!this.s.dt.page.info().serverSide) {
  1303. for (var _i = 0, _a = this.s.dt.rows().indexes().toArray(); _i < _a.length; _i++) {
  1304. var index = _a[_i];
  1305. this._populatePaneArray(index, this.s.rowData.arrayFilter, settings);
  1306. }
  1307. }
  1308. };
  1309. /**
  1310. * This method decides whether a row should contribute to the pane or not
  1311. *
  1312. * @param filter the value that the row is to be filtered on
  1313. * @param dataIndex the row index
  1314. */
  1315. SearchPane.prototype._search = function (filter, dataIndex) {
  1316. var colOpts = this.s.colOpts;
  1317. var table = this.s.dt;
  1318. // For each item selected in the pane, check if it is available in the cell
  1319. for (var _i = 0, _a = this.s.selections; _i < _a.length; _i++) {
  1320. var colSelect = _a[_i];
  1321. if (typeof colSelect === 'string' && typeof filter === 'string') {
  1322. // The filter value will not have the &amp; in place but a &,
  1323. // so we need to do a replace to make sure that they will match
  1324. colSelect = this._escapeHTML(colSelect);
  1325. }
  1326. // if the filter is an array then is the column present in it
  1327. if (Array.isArray(filter)) {
  1328. if (colOpts.combiner === 'and') {
  1329. if (!filter.includes(colSelect)) {
  1330. return false;
  1331. }
  1332. }
  1333. else if (filter.includes(colSelect)) {
  1334. return true;
  1335. }
  1336. }
  1337. // if the filter is a function then does it meet the criteria of that function or not
  1338. else if (typeof colSelect === 'function') {
  1339. if (colSelect.call(table, table.row(dataIndex).data(), dataIndex)) {
  1340. if (colOpts.combiner === 'or') {
  1341. return true;
  1342. }
  1343. }
  1344. // If the combiner is an "and" then we need to check against all possible selections
  1345. // so if it fails here then the and is not met and return false
  1346. else if (colOpts.combiner === 'and') {
  1347. return false;
  1348. }
  1349. }
  1350. // otherwise if the two filter values are equal then return true
  1351. else if (filter === colSelect ||
  1352. // Loose type checking incase number type in column comparing to a string
  1353. // eslint-disable-next-line eqeqeq
  1354. !(typeof filter === 'string' && filter.length === 0) && filter == colSelect ||
  1355. colSelect === null && typeof filter === 'string' && filter === '') {
  1356. return true;
  1357. }
  1358. }
  1359. // If the combiner is an and then we need to check against all possible selections
  1360. // so return true here if so because it would have returned false earlier if it had failed
  1361. if (colOpts.combiner === 'and') {
  1362. return true;
  1363. }
  1364. // Otherwise it hasn't matched with anything by this point so it must be false
  1365. return false;
  1366. };
  1367. /**
  1368. * Creates the contents of the searchCont div
  1369. *
  1370. * NOTE This is overridden when semantic ui styling in order to integrate the search button into the text box.
  1371. */
  1372. SearchPane.prototype._searchContSetup = function () {
  1373. if (this.c.controls && this.s.colOpts.controls) {
  1374. this.dom.searchButton.appendTo(this.dom.searchLabelCont);
  1375. }
  1376. if (!(this.c.dtOpts.searching === false ||
  1377. this.s.colOpts.dtOpts.searching === false ||
  1378. this.s.customPaneSettings &&
  1379. this.s.customPaneSettings.dtOpts &&
  1380. this.s.customPaneSettings.dtOpts.searching !== undefined &&
  1381. !this.s.customPaneSettings.dtOpts.searching)) {
  1382. this.dom.searchLabelCont.appendTo(this.dom.searchCont);
  1383. }
  1384. };
  1385. /**
  1386. * Adds outline to the pane when a selection has been made
  1387. */
  1388. SearchPane.prototype._searchExtras = function () {
  1389. var updating = this.s.updating;
  1390. this.s.updating = true;
  1391. var filters = this.s.dtPane.rows({ selected: true }).data().pluck('filter').toArray();
  1392. var nullIndex = filters.indexOf(this.emptyMessage());
  1393. var container = $$4(this.s.dtPane.table().container());
  1394. // If null index is found then search for empty cells as a filter.
  1395. if (nullIndex > -1) {
  1396. filters[nullIndex] = '';
  1397. }
  1398. // If a filter has been applied then outline the respective pane, remove it when it no longer is.
  1399. if (filters.length > 0) {
  1400. container.addClass(this.classes.selected);
  1401. }
  1402. else if (filters.length === 0) {
  1403. container.removeClass(this.classes.selected);
  1404. }
  1405. this.s.updating = updating;
  1406. };
  1407. SearchPane.version = '2.0.0-dev';
  1408. SearchPane.classes = {
  1409. bordered: 'dtsp-bordered',
  1410. buttonGroup: 'dtsp-buttonGroup',
  1411. buttonSub: 'dtsp-buttonSub',
  1412. caret: 'dtsp-caret',
  1413. clear: 'dtsp-clear',
  1414. clearAll: 'dtsp-clearAll',
  1415. clearButton: 'clearButton',
  1416. collapseAll: 'dtsp-collapseAll',
  1417. collapseButton: 'dtsp-collapseButton',
  1418. container: 'dtsp-searchPane',
  1419. countButton: 'dtsp-countButton',
  1420. disabledButton: 'dtsp-disabledButton',
  1421. hidden: 'dtsp-hidden',
  1422. hide: 'dtsp-hide',
  1423. layout: 'dtsp-',
  1424. name: 'dtsp-name',
  1425. nameButton: 'dtsp-nameButton',
  1426. nameCont: 'dtsp-nameCont',
  1427. narrow: 'dtsp-narrow',
  1428. paneButton: 'dtsp-paneButton',
  1429. paneInputButton: 'dtsp-paneInputButton',
  1430. pill: 'dtsp-pill',
  1431. rotated: 'dtsp-rotated',
  1432. search: 'dtsp-search',
  1433. searchCont: 'dtsp-searchCont',
  1434. searchIcon: 'dtsp-searchIcon',
  1435. searchLabelCont: 'dtsp-searchButtonCont',
  1436. selected: 'dtsp-selected',
  1437. smallGap: 'dtsp-smallGap',
  1438. subRow1: 'dtsp-subRow1',
  1439. subRow2: 'dtsp-subRow2',
  1440. subRowsContainer: 'dtsp-subRowsContainer',
  1441. title: 'dtsp-title',
  1442. topRow: 'dtsp-topRow'
  1443. };
  1444. // Define SearchPanes default options
  1445. SearchPane.defaults = {
  1446. clear: true,
  1447. collapse: true,
  1448. combiner: 'or',
  1449. container: function (dt) {
  1450. return dt.table().container();
  1451. },
  1452. controls: true,
  1453. dtOpts: {},
  1454. emptyMessage: null,
  1455. hideCount: false,
  1456. i18n: {
  1457. clearPane: '&times;',
  1458. count: '{total}',
  1459. emptyMessage: '<em>No data</em>'
  1460. },
  1461. initCollapsed: false,
  1462. layout: 'auto',
  1463. name: undefined,
  1464. orderable: true,
  1465. orthogonal: {
  1466. display: 'display',
  1467. filter: 'filter',
  1468. hideCount: false,
  1469. search: 'filter',
  1470. show: undefined,
  1471. sort: 'sort',
  1472. threshold: 0.6,
  1473. type: 'type',
  1474. viewCount: true
  1475. },
  1476. preSelect: [],
  1477. threshold: 0.6,
  1478. viewCount: true
  1479. };
  1480. return SearchPane;
  1481. }());
  1482. var __extends$4 = (window && window.__extends) || (function () {
  1483. var extendStatics = function (d, b) {
  1484. extendStatics = Object.setPrototypeOf ||
  1485. ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
  1486. function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
  1487. return extendStatics(d, b);
  1488. };
  1489. return function (d, b) {
  1490. extendStatics(d, b);
  1491. function __() { this.constructor = d; }
  1492. d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
  1493. };
  1494. })();
  1495. var SearchPaneST = /** @class */ (function (_super) {
  1496. __extends$4(SearchPaneST, _super);
  1497. function SearchPaneST(paneSettings, opts, index, panesContainer, panes) {
  1498. return _super.call(this, paneSettings, opts, index, panesContainer, panes) || this;
  1499. }
  1500. /**
  1501. * Populates the SearchPane based off of the data that has been recieved from the server
  1502. *
  1503. * This method overrides SearchPane's _serverPopulate() method
  1504. *
  1505. * @param dataIn The data that has been sent from the server
  1506. */
  1507. SearchPaneST.prototype._serverPopulate = function (dataIn) {
  1508. this.s.rowData.binsShown = {};
  1509. this.s.rowData.arrayFilter = [];
  1510. if (dataIn.tableLength !== undefined) {
  1511. this.s.tableLength = dataIn.tableLength;
  1512. this.s.rowData.totalOptions = this.s.tableLength;
  1513. }
  1514. else if (this.s.tableLength === null || this.s.dt.rows()[0].length > this.s.tableLength) {
  1515. this.s.tableLength = this.s.dt.rows()[0].length;
  1516. this.s.rowData.totalOptions = this.s.tableLength;
  1517. }
  1518. var colTitle = this.s.dt.column(this.s.index).dataSrc();
  1519. // If there is SP data for this column add it to the data array and bin
  1520. if (dataIn.searchPanes.options[colTitle] !== undefined) {
  1521. for (var _i = 0, _a = dataIn.searchPanes.options[colTitle]; _i < _a.length; _i++) {
  1522. var dataPoint = _a[_i];
  1523. this.s.rowData.arrayFilter.push({
  1524. display: dataPoint.label,
  1525. filter: dataPoint.value,
  1526. shown: +dataPoint.count,
  1527. sort: dataPoint.label,
  1528. total: +dataPoint.total,
  1529. type: dataPoint.label
  1530. });
  1531. this.s.rowData.binsShown[dataPoint.value] = +dataPoint.count;
  1532. this.s.rowData.bins[dataPoint.value] = +dataPoint.total;
  1533. }
  1534. }
  1535. var binLength = Object.keys(this.s.rowData.bins).length;
  1536. var uniqueRatio = this._uniqueRatio(binLength, this.s.tableLength);
  1537. // Don't show the pane if there isnt enough variance in the data, or there is only 1 entry for that pane
  1538. if (!this.s.colOpts.show &&
  1539. this.s.displayed === false &&
  1540. ((this.s.colOpts.show === undefined && this.s.colOpts.threshold === null ?
  1541. uniqueRatio > this.c.threshold :
  1542. uniqueRatio > this.s.colOpts.threshold) ||
  1543. this.s.colOpts.show !== true && binLength <= 1)) {
  1544. this.dom.container.addClass(this.classes.hidden);
  1545. this.s.displayed = false;
  1546. return;
  1547. }
  1548. // Store the original data
  1549. this.s.rowData.arrayOriginal = this.s.rowData.arrayFilter;
  1550. this.s.rowData.binsOriginal = this.s.rowData.bins;
  1551. // Flag this pane as being displayed
  1552. this.s.displayed = true;
  1553. // If the pane exists
  1554. if (this.s.dtPane) {
  1555. // Not the selections that have been made and remove all of the rows
  1556. var selected = this.s.serverSelect;
  1557. this.s.dtPane.rows().remove();
  1558. // Add the rows that are to be shown into the pane
  1559. for (var _b = 0, _c = this.s.rowData.arrayFilter; _b < _c.length; _b++) {
  1560. var data = _c[_b];
  1561. if (this._shouldAddRow(data)) {
  1562. var row = this.addRow(data.display, data.filter, data.sort, data.type);
  1563. // Select the row if it was selected before
  1564. for (var i = 0; i < selected.length; i++) {
  1565. var selection = selected[i];
  1566. if (selection.filter === data.filter) {
  1567. // This flag stops another request being made to the server
  1568. this.s.serverSelecting = true;
  1569. row.select();
  1570. this.s.serverSelecting = false;
  1571. // Remove the selection from the to select list and add it to the selected list
  1572. selected.splice(i, 1);
  1573. this.s.selections.push(data.filter);
  1574. break;
  1575. }
  1576. }
  1577. }
  1578. }
  1579. // Remake any selections that are no longer present
  1580. for (var _d = 0, selected_1 = selected; _d < selected_1.length; _d++) {
  1581. var selection = selected_1[_d];
  1582. for (var _e = 0, _f = this.s.rowData.arrayOriginal; _e < _f.length; _e++) {
  1583. var data = _f[_e];
  1584. if (data.filter === selection.filter) {
  1585. var row = this.addRow(data.display, data.filter, data.sort, data.type);
  1586. this.s.serverSelecting = true;
  1587. row.select();
  1588. this.s.serverSelecting = false;
  1589. this.s.selections.push(data.filter);
  1590. }
  1591. }
  1592. }
  1593. // Store the selected rows
  1594. this.s.serverSelect = this.s.dtPane.rows({ selected: true }).data().toArray();
  1595. // Update the pane
  1596. this.s.dtPane.draw();
  1597. }
  1598. };
  1599. /**
  1600. * This method updates the rows and their data within the SearchPanes
  1601. *
  1602. * SearchPaneCascade overrides this method
  1603. */
  1604. SearchPaneST.prototype.updateRows = function () {
  1605. if (!this.s.dt.page.info().serverSide) {
  1606. // Get the latest count values from the table
  1607. this.s.rowData.binsShown = {};
  1608. for (var _i = 0, _a = this.s.dt.rows({ search: 'applied' }).indexes().toArray(); _i < _a.length; _i++) {
  1609. var index = _a[_i];
  1610. this._updateShown(index, this.s.dt.settings()[0], this.s.rowData.binsShown);
  1611. }
  1612. }
  1613. // Update the rows data to show the current counts
  1614. for (var _b = 0, _c = this.s.dtPane.rows().data().toArray(); _b < _c.length; _b++) {
  1615. var row = _c[_b];
  1616. row.shown = typeof this.s.rowData.binsShown[row.filter] === 'number' ?
  1617. this.s.rowData.binsShown[row.filter] :
  1618. 0;
  1619. this.s.dtPane.row(row.index).data(row);
  1620. }
  1621. // Show updates in the pane
  1622. this.s.dtPane.draw();
  1623. this.s.dtPane.table().node().parentNode.scrollTop = this.s.scrollTop;
  1624. };
  1625. /**
  1626. * Remove functionality from makeSelection - needs to be more advanced when tracking selections
  1627. */
  1628. SearchPaneST.prototype._makeSelection = function () {
  1629. return;
  1630. };
  1631. /**
  1632. * Blank method to remove reloading of selected rows - needs to be more advanced when tracking selections
  1633. */
  1634. SearchPaneST.prototype._reloadSelect = function () {
  1635. return;
  1636. };
  1637. /**
  1638. * Decides if a row should be added when being added from the server
  1639. *
  1640. * Overridden by SearchPaneCascade
  1641. *
  1642. * @param data the row data
  1643. * @returns boolean indicating if the row should be added or not
  1644. */
  1645. // eslint-disable-next-line @typescript-eslint/no-unused-vars
  1646. SearchPaneST.prototype._shouldAddRow = function (data) {
  1647. return true;
  1648. };
  1649. /**
  1650. * Updates the server selection list where appropriate
  1651. */
  1652. SearchPaneST.prototype._updateSelection = function () {
  1653. if (this.s.dt.page.info().serverSide && !this.s.updating && !this.s.serverSelecting) {
  1654. this.s.serverSelect = this.s.dtPane.rows({ selected: true }).data().toArray();
  1655. }
  1656. };
  1657. /**
  1658. * Used when binning the data for a column
  1659. *
  1660. * @param rowIdx The current row that is to be added to the bins
  1661. * @param settings The datatables settings object
  1662. * @param bins The bins object that is to be incremented
  1663. */
  1664. SearchPaneST.prototype._updateShown = function (rowIdx, settings, bins) {
  1665. if (bins === void 0) { bins = this.s.rowData.binsShown; }
  1666. var orth = typeof this.s.colOpts.orthogonal === 'string'
  1667. ? this.s.colOpts.orthogonal
  1668. : this.s.colOpts.orthogonal.search;
  1669. var filter = settings.oApi._fnGetCellData(settings, rowIdx, this.s.index, orth);
  1670. var add = function (f) {
  1671. if (!bins[f]) {
  1672. bins[f] = 1;
  1673. }
  1674. else {
  1675. bins[f]++;
  1676. }
  1677. };
  1678. if (Array.isArray(filter)) {
  1679. for (var _i = 0, filter_1 = filter; _i < filter_1.length; _i++) {
  1680. var f = filter_1[_i];
  1681. add(f);
  1682. }
  1683. }
  1684. else {
  1685. add(filter);
  1686. }
  1687. };
  1688. return SearchPaneST;
  1689. }(SearchPane));
  1690. var __extends$3 = (window && window.__extends) || (function () {
  1691. var extendStatics = function (d, b) {
  1692. extendStatics = Object.setPrototypeOf ||
  1693. ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
  1694. function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
  1695. return extendStatics(d, b);
  1696. };
  1697. return function (d, b) {
  1698. extendStatics(d, b);
  1699. function __() { this.constructor = d; }
  1700. d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
  1701. };
  1702. })();
  1703. var $$3;
  1704. function setJQuery$3(jq) {
  1705. $$3 = jq;
  1706. }
  1707. var SearchPaneViewTotal = /** @class */ (function (_super) {
  1708. __extends$3(SearchPaneViewTotal, _super);
  1709. function SearchPaneViewTotal(paneSettings, opts, index, panesContainer, panes) {
  1710. var _this = this;
  1711. var override = {
  1712. i18n: {
  1713. countFiltered: '{shown} ({total})'
  1714. }
  1715. };
  1716. _this = _super.call(this, paneSettings, $$3.extend(override, opts), index, panesContainer, panes) || this;
  1717. return _this;
  1718. }
  1719. /**
  1720. * Gets the message that is to be used to indicate the count for each SearchPane row
  1721. *
  1722. * This method overrides _getMessage() in SearchPane and is overridden by SearchPaneCascadeViewTotal
  1723. *
  1724. * @param row The row object that is being processed
  1725. * @returns string - the message that is to be shown for the count of each entry
  1726. */
  1727. SearchPaneViewTotal.prototype._getMessage = function (row) {
  1728. var countMessage = this.s.dt.i18n('searchPanes.count', this.c.i18n.count);
  1729. var filteredMessage = this.s.dt.i18n('searchPanes.countFiltered', this.c.i18n.countFiltered);
  1730. return (this.s.filteringActive ? filteredMessage : countMessage)
  1731. .replace(/{total}/g, row.total)
  1732. .replace(/{shown}/g, row.shown);
  1733. };
  1734. /**
  1735. * Overrides the blank method in SearchPane to return the number of times a given value is currently being displayed
  1736. *
  1737. * @param filter The filter value
  1738. * @returns number - The number of times the value is shown
  1739. */
  1740. SearchPaneViewTotal.prototype._getShown = function (filter) {
  1741. return this.s.rowData.binsShown && this.s.rowData.binsShown[filter] ?
  1742. this.s.rowData.binsShown[filter] :
  1743. 0;
  1744. };
  1745. return SearchPaneViewTotal;
  1746. }(SearchPaneST));
  1747. var __extends$2 = (window && window.__extends) || (function () {
  1748. var extendStatics = function (d, b) {
  1749. extendStatics = Object.setPrototypeOf ||
  1750. ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
  1751. function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
  1752. return extendStatics(d, b);
  1753. };
  1754. return function (d, b) {
  1755. extendStatics(d, b);
  1756. function __() { this.constructor = d; }
  1757. d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
  1758. };
  1759. })();
  1760. var $$2;
  1761. function setJQuery$2(jq) {
  1762. $$2 = jq;
  1763. }
  1764. var SearchPaneCascade = /** @class */ (function (_super) {
  1765. __extends$2(SearchPaneCascade, _super);
  1766. function SearchPaneCascade(paneSettings, opts, index, panesContainer, panes) {
  1767. var _this = this;
  1768. var override = {
  1769. i18n: {
  1770. count: '{shown}'
  1771. }
  1772. };
  1773. _this = _super.call(this, paneSettings, $$2.extend(override, opts), index, panesContainer, panes) || this;
  1774. return _this;
  1775. }
  1776. /**
  1777. * This method updates the rows and their data within the SearchPanes
  1778. *
  1779. * This overrides the method in SearchPane
  1780. */
  1781. SearchPaneCascade.prototype.updateRows = function () {
  1782. // Note the currently selected values in the pane and remove all of the rows
  1783. var selected = this.s.dtPane.rows({ selected: true }).data().toArray();
  1784. if (this.s.colOpts.options ||
  1785. this.s.customPaneSettings && this.s.customPaneSettings.options) {
  1786. // If there are custom options set or it is a custom pane then get them
  1787. this._getComparisonRows();
  1788. var rows = this.s.dtPane.rows().toArray()[0];
  1789. for (var i = 0; i < rows.length; i++) {
  1790. var row = this.s.dtPane.row(rows[i]);
  1791. var rowData = row.data();
  1792. if (rowData === undefined) {
  1793. continue;
  1794. }
  1795. if (rowData.shown === 0) {
  1796. row.remove();
  1797. rows = this.s.dtPane.rows().toArray()[0];
  1798. i--;
  1799. continue;
  1800. }
  1801. for (var _i = 0, selected_1 = selected; _i < selected_1.length; _i++) {
  1802. var selection = selected_1[_i];
  1803. if (rowData.filter === selection.filter) {
  1804. row.select();
  1805. selected.splice(i, 1);
  1806. this.s.selections.push(rowData.filter);
  1807. break;
  1808. }
  1809. }
  1810. }
  1811. }
  1812. else {
  1813. if (!this.s.dt.page.info().serverSide) {
  1814. // Get the latest count values from the table
  1815. this._activePopulatePane();
  1816. this.s.rowData.binsShown = {};
  1817. for (var _a = 0, _b = this.s.dt.rows({ search: 'applied' }).indexes().toArray(); _a < _b.length; _a++) {
  1818. var index = _b[_a];
  1819. this._updateShown(index, this.s.dt.settings()[0], this.s.rowData.binsShown);
  1820. }
  1821. }
  1822. this.s.dtPane.rows().remove();
  1823. // Go over all of the rows that could be displayed
  1824. for (var _c = 0, _d = this.s.rowData.arrayFilter; _c < _d.length; _c++) {
  1825. var data = _d[_c];
  1826. // Cascade - If there are no rows present in the table don't show the option
  1827. if (data.shown === 0) {
  1828. continue;
  1829. }
  1830. // Add the row to the pane
  1831. var row = this.addRow(data.display, data.filter, data.sort, data.type, undefined);
  1832. // Check if this row was selected
  1833. for (var i = 0; i < selected.length; i++) {
  1834. var selection = selected[i];
  1835. if (selection.filter === data.filter) {
  1836. row.select();
  1837. // Remove the row from the to find list and then add it to the selections list
  1838. selected.splice(i, 1);
  1839. this.s.selections.push(data.filter);
  1840. break;
  1841. }
  1842. }
  1843. }
  1844. // Add all of the rows that were previously selected but aren't any more
  1845. for (var _e = 0, selected_2 = selected; _e < selected_2.length; _e++) {
  1846. var selection = selected_2[_e];
  1847. for (var _f = 0, _g = this.s.rowData.arrayOriginal; _f < _g.length; _f++) {
  1848. var data = _g[_f];
  1849. if (data.filter === selection.filter) {
  1850. var row = this.addRow(data.display, data.filter, data.sort, data.type, undefined);
  1851. row.select();
  1852. this.s.selections.push(data.filter);
  1853. }
  1854. }
  1855. }
  1856. }
  1857. // Show updates in the pane
  1858. this.s.dtPane.draw();
  1859. this.s.dtPane.table().node().parentNode.scrollTop = this.s.scrollTop;
  1860. // If client side updated the tables results
  1861. if (!this.s.dt.page.info().serverSide) {
  1862. this.s.dt.draw();
  1863. }
  1864. };
  1865. /**
  1866. * Fill the array with the values that are currently being displayed in the table
  1867. */
  1868. SearchPaneCascade.prototype._activePopulatePane = function () {
  1869. this.s.rowData.arrayFilter = [];
  1870. this.s.rowData.bins = {};
  1871. var settings = this.s.dt.settings()[0];
  1872. if (!this.s.dt.page.info().serverSide) {
  1873. for (var _i = 0, _a = this.s.dt.rows({ search: 'applied' }).indexes().toArray(); _i < _a.length; _i++) {
  1874. var index = _a[_i];
  1875. this._populatePaneArray(index, this.s.rowData.arrayFilter, settings);
  1876. }
  1877. }
  1878. };
  1879. SearchPaneCascade.prototype._getComparisonRows = function () {
  1880. // Find the appropriate options depending on whether this is a pane for a specific column or a custom pane
  1881. var options = this.s.colOpts.options
  1882. ? this.s.colOpts.options
  1883. : this.s.customPaneSettings && this.s.customPaneSettings.options
  1884. ? this.s.customPaneSettings.options
  1885. : undefined;
  1886. if (options === undefined) {
  1887. return;
  1888. }
  1889. var allRows = this.s.dt.rows();
  1890. var shownRows = this.s.dt.rows({ search: 'applied' });
  1891. var tableValsTotal = allRows.data().toArray();
  1892. var tableValsShown = shownRows.data().toArray();
  1893. var rows = [];
  1894. // Clear all of the other rows from the pane, only custom options are to be displayed when they are defined
  1895. this.s.dtPane.clear();
  1896. this.s.indexes = [];
  1897. for (var _i = 0, options_1 = options; _i < options_1.length; _i++) {
  1898. var comp = options_1[_i];
  1899. // Initialise the object which is to be placed in the row
  1900. var insert = comp.label !== '' ?
  1901. comp.label :
  1902. this.emptyMessage();
  1903. var comparisonObj = {
  1904. className: comp.className,
  1905. display: insert,
  1906. filter: typeof comp.value === 'function' ? comp.value : [],
  1907. shown: 0,
  1908. sort: insert,
  1909. total: 0,
  1910. type: insert
  1911. };
  1912. // If a custom function is in place
  1913. if (typeof comp.value === 'function') {
  1914. // Count the number of times the function evaluates to true for the original data in the Table
  1915. for (var i = 0; i < tableValsTotal.length; i++) {
  1916. if (comp.value.call(this.s.dt, tableValsTotal[i], allRows[0][i])) {
  1917. comparisonObj.total++;
  1918. }
  1919. }
  1920. for (var i = 0; i < tableValsShown.length; i++) {
  1921. if (comp.value.call(this.s.dt, tableValsShown[i], shownRows[0][i])) {
  1922. comparisonObj.shown++;
  1923. }
  1924. }
  1925. // Update the comparisonObj
  1926. if (typeof comparisonObj.filter !== 'function') {
  1927. comparisonObj.filter.push(comp.filter);
  1928. }
  1929. }
  1930. rows.push(this.addRow(comparisonObj.display, comparisonObj.filter, comparisonObj.sort, comparisonObj.type, comparisonObj.className, comparisonObj.total, comparisonObj.shown));
  1931. }
  1932. return rows;
  1933. };
  1934. /**
  1935. * Gets the message that is to be used to indicate the count for each SearchPane row
  1936. *
  1937. * This method overrides _getMessage() in SearchPane and is overridden by SearchPaneCascadeViewTotal
  1938. *
  1939. * @param row The row object that is being processed
  1940. * @returns string - the message that is to be shown for the count of each entry
  1941. */
  1942. SearchPaneCascade.prototype._getMessage = function (row) {
  1943. return this.s.dt.i18n('searchPanes.count', this.c.i18n.count)
  1944. .replace(/{total}/g, row.total)
  1945. .replace(/{shown}/g, row.shown);
  1946. };
  1947. /**
  1948. * Overrides the blank method in SearchPane to return the number of times a given value is currently being displayed
  1949. *
  1950. * @param filter The filter value
  1951. * @returns number - The number of times the value is shown
  1952. */
  1953. SearchPaneCascade.prototype._getShown = function (filter) {
  1954. return this.s.rowData.binsShown && this.s.rowData.binsShown[filter] ?
  1955. this.s.rowData.binsShown[filter] :
  1956. 0;
  1957. };
  1958. /**
  1959. * Decides if a row should be added when being added from the server
  1960. *
  1961. * Overrides method in by SearchPaneST
  1962. *
  1963. * @param data the row data
  1964. * @returns boolean indicating if the row should be added or not
  1965. */
  1966. SearchPaneCascade.prototype._shouldAddRow = function (data) {
  1967. return data.shown > 0;
  1968. };
  1969. return SearchPaneCascade;
  1970. }(SearchPaneST));
  1971. var __extends$1 = (window && window.__extends) || (function () {
  1972. var extendStatics = function (d, b) {
  1973. extendStatics = Object.setPrototypeOf ||
  1974. ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
  1975. function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
  1976. return extendStatics(d, b);
  1977. };
  1978. return function (d, b) {
  1979. extendStatics(d, b);
  1980. function __() { this.constructor = d; }
  1981. d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
  1982. };
  1983. })();
  1984. var $$1;
  1985. function setJQuery$1(jq) {
  1986. $$1 = jq;
  1987. }
  1988. var SearchPaneCascadeViewTotal = /** @class */ (function (_super) {
  1989. __extends$1(SearchPaneCascadeViewTotal, _super);
  1990. function SearchPaneCascadeViewTotal(paneSettings, opts, index, panesContainer, panes) {
  1991. var _this = this;
  1992. var override = {
  1993. i18n: {
  1994. count: '{total}',
  1995. countFiltered: '{shown} ({total})'
  1996. }
  1997. };
  1998. _this = _super.call(this, paneSettings, $$1.extend(override, opts), index, panesContainer, panes) || this;
  1999. return _this;
  2000. }
  2001. /**
  2002. * Fill the array with the values that are currently being displayed in the table
  2003. *
  2004. * This method overrides _activePopulatePane() in SearchPaneCascade
  2005. */
  2006. SearchPaneCascadeViewTotal.prototype._activePopulatePane = function () {
  2007. this.s.rowData.arrayFilter = [];
  2008. this.s.rowData.binsShown = {};
  2009. var settings = this.s.dt.settings()[0];
  2010. if (!this.s.dt.page.info().serverSide) {
  2011. for (var _i = 0, _a = this.s.dt.rows({ search: 'applied' }).indexes().toArray(); _i < _a.length; _i++) {
  2012. var index = _a[_i];
  2013. this._populatePaneArray(index, this.s.rowData.arrayFilter, settings, this.s.rowData.binsShown);
  2014. }
  2015. }
  2016. };
  2017. /**
  2018. * Gets the message that is to be used to indicate the count for each SearchPane row
  2019. *
  2020. * This method overrides _getMessage() in SearchPaneCascade
  2021. *
  2022. * @param row The row object that is being processed
  2023. * @returns string - the message that is to be shown for the count of each entry
  2024. */
  2025. SearchPaneCascadeViewTotal.prototype._getMessage = function (row) {
  2026. var countMessage = this.s.dt.i18n('searchPanes.count', this.c.i18n.count);
  2027. var filteredMessage = this.s.dt.i18n('searchPanes.countFiltered', this.c.i18n.countFiltered);
  2028. return (this.s.filteringActive ? filteredMessage : countMessage)
  2029. .replace(/{total}/g, row.total)
  2030. .replace(/{shown}/g, row.shown);
  2031. };
  2032. return SearchPaneCascadeViewTotal;
  2033. }(SearchPaneCascade));
  2034. var $;
  2035. var dataTable;
  2036. function setJQuery(jq) {
  2037. $ = jq;
  2038. dataTable = jq.fn.dataTable;
  2039. }
  2040. var SearchPanes = /** @class */ (function () {
  2041. function SearchPanes(paneSettings, opts, fromPreInit, paneClass) {
  2042. var _this = this;
  2043. if (fromPreInit === void 0) { fromPreInit = false; }
  2044. if (paneClass === void 0) { paneClass = SearchPane; }
  2045. // Check that the required version of DataTables is included
  2046. if (!dataTable || !dataTable.versionCheck || !dataTable.versionCheck('1.10.0')) {
  2047. throw new Error('SearchPane requires DataTables 1.10 or newer');
  2048. }
  2049. // Check that Select is included
  2050. // eslint-disable-next-line no-extra-parens
  2051. if (!dataTable.select) {
  2052. throw new Error('SearchPane requires Select');
  2053. }
  2054. var table = new dataTable.Api(paneSettings);
  2055. this.classes = $.extend(true, {}, SearchPanes.classes);
  2056. // Get options from user
  2057. this.c = $.extend(true, {}, SearchPanes.defaults, opts);
  2058. // Add extra elements to DOM object including clear
  2059. this.dom = {
  2060. clearAll: $('<button type="button"/>')
  2061. .addClass(this.classes.clearAll)
  2062. .html(table.i18n('searchPanes.clearMessage', this.c.i18n.clearMessage)),
  2063. collapseAll: $('<button type="button"/>')
  2064. .addClass(this.classes.collapseAll)
  2065. .html(table.i18n('searchPanes.collapseMessage', this.c.i18n.collapseMessage)),
  2066. container: $('<div/>').addClass(this.classes.panes).html(table.i18n('searchPanes.loadMessage', this.c.i18n.loadMessage)),
  2067. emptyMessage: $('<div/>').addClass(this.classes.emptyMessage),
  2068. panes: $('<div/>').addClass(this.classes.container),
  2069. showAll: $('<button type="button"/>')
  2070. .addClass(this.classes.showAll)
  2071. .addClass(this.classes.disabledButton)
  2072. .attr('disabled', 'true')
  2073. .html(table.i18n('searchPanes.showMessage', this.c.i18n.showMessage)),
  2074. title: $('<div/>').addClass(this.classes.title),
  2075. titleRow: $('<div/>').addClass(this.classes.titleRow)
  2076. };
  2077. this.s = {
  2078. colOpts: [],
  2079. dt: table,
  2080. filterCount: 0,
  2081. minPaneWidth: 260.0,
  2082. page: 0,
  2083. paging: false,
  2084. pagingST: false,
  2085. paneClass: paneClass,
  2086. panes: [],
  2087. selectionList: [],
  2088. serverData: {},
  2089. stateRead: false,
  2090. updating: false
  2091. };
  2092. // Do not reinitialise if already initialised on table
  2093. if (table.settings()[0]._searchPanes) {
  2094. return;
  2095. }
  2096. this._getState();
  2097. if (this.s.dt.page.info().serverSide) {
  2098. var hostSettings = this.s.dt.settings()[0];
  2099. // Listener to get the data into the server request before it is made
  2100. this.s.dt.on('preXhr.dtsps', function (e, settings, data) {
  2101. if (hostSettings !== settings) {
  2102. return;
  2103. }
  2104. if (data.searchPanes === undefined) {
  2105. data.searchPanes = {};
  2106. }
  2107. if (data.searchPanes_null === undefined) {
  2108. data.searchPanes_null = {};
  2109. }
  2110. var src;
  2111. for (var _i = 0, _a = _this.s.selectionList; _i < _a.length; _i++) {
  2112. var selection = _a[_i];
  2113. src = _this.s.dt.column(selection.column).dataSrc();
  2114. if (data.searchPanes[src] === undefined) {
  2115. data.searchPanes[src] = {};
  2116. }
  2117. if (data.searchPanes_null[src] === undefined) {
  2118. data.searchPanes_null[src] = {};
  2119. }
  2120. for (var i = 0; i < selection.rows.length; i++) {
  2121. data.searchPanes[src][i] = selection.rows[i];
  2122. if (data.searchPanes[src][i] === null) {
  2123. data.searchPanes_null[src][i] = true;
  2124. }
  2125. }
  2126. }
  2127. if (_this.s.selectionList.length > 0) {
  2128. data.searchPanesLast = src;
  2129. }
  2130. });
  2131. }
  2132. this._setXHR();
  2133. table.settings()[0]._searchPanes = this;
  2134. if (this.s.dt.settings()[0]._bInitComplete || fromPreInit) {
  2135. this._paneDeclare(table, paneSettings, opts);
  2136. }
  2137. else {
  2138. table.one('preInit.dtsps', function () {
  2139. _this._paneDeclare(table, paneSettings, opts);
  2140. });
  2141. }
  2142. return this;
  2143. }
  2144. /**
  2145. * Clear the selections of all of the panes
  2146. */
  2147. SearchPanes.prototype.clearSelections = function () {
  2148. for (var _i = 0, _a = this.s.panes; _i < _a.length; _i++) {
  2149. var pane = _a[_i];
  2150. if (pane.s.dtPane) {
  2151. pane.s.scrollTop = pane.s.dtPane.table().node().parentNode.scrollTop;
  2152. }
  2153. }
  2154. // Load in all of the searchBoxes in the documents
  2155. var searches = this.dom.container.find('.' + this.classes.search.replace(/\s+/g, '.'));
  2156. // For each searchBox set the input text to be empty and then trigger
  2157. // an input on them so that they no longer filter the panes
  2158. searches.each(function () {
  2159. $(this).val('').trigger('input');
  2160. });
  2161. // Clear the selectionList
  2162. this.s.selectionList = [];
  2163. var returnArray = [];
  2164. for (var _b = 0, _c = this.s.panes; _b < _c.length; _b++) {
  2165. var pane = _c[_b];
  2166. if (pane.s.dtPane) {
  2167. returnArray.push(pane.clearPane());
  2168. }
  2169. }
  2170. return returnArray;
  2171. };
  2172. /**
  2173. * returns the container node for the searchPanes
  2174. */
  2175. SearchPanes.prototype.getNode = function () {
  2176. return this.dom.container;
  2177. };
  2178. /**
  2179. * rebuilds all of the panes
  2180. */
  2181. SearchPanes.prototype.rebuild = function (targetIdx, maintainSelection) {
  2182. if (targetIdx === void 0) { targetIdx = false; }
  2183. if (maintainSelection === void 0) { maintainSelection = false; }
  2184. this.dom.emptyMessage.detach();
  2185. // As a rebuild from scratch is required, empty the searchpanes container.
  2186. if (targetIdx === false) {
  2187. this.dom.panes.empty();
  2188. }
  2189. // Rebuild each pane individually, if a specific pane has been selected then only rebuild that one
  2190. var returnArray = [];
  2191. for (var _i = 0, _a = this.s.panes; _i < _a.length; _i++) {
  2192. var pane = _a[_i];
  2193. if (targetIdx === false || pane.s.index === targetIdx) {
  2194. pane.clearData();
  2195. pane.rebuildPane(this.s.dt.page.info().serverSide ?
  2196. this.s.serverData :
  2197. undefined, maintainSelection);
  2198. this.dom.panes.append(pane.dom.container);
  2199. returnArray.push(pane);
  2200. }
  2201. }
  2202. this._updateSelection();
  2203. // Attach panes, clear buttons, and title bar to the document
  2204. this._updateFilterCount();
  2205. this._attachPaneContainer();
  2206. this._initSelectionListeners(false);
  2207. // If the selections are to be maintained, then it is safe to assume that paging is also to be maintained
  2208. // Otherwise, the paging should be reset
  2209. this.s.dt.draw(!maintainSelection);
  2210. // Resize the panes incase there has been a change
  2211. this.resizePanes();
  2212. // If a single pane has been rebuilt then return only that pane
  2213. return returnArray.length === 1 ? returnArray[0] : returnArray;
  2214. };
  2215. /**
  2216. * Resizes all of the panes
  2217. */
  2218. SearchPanes.prototype.resizePanes = function () {
  2219. if (this.c.layout === 'auto') {
  2220. var contWidth = $(this.s.dt.searchPanes.container()).width();
  2221. var target = Math.floor(contWidth / this.s.minPaneWidth); // The neatest number of panes per row
  2222. var highest_1 = 1;
  2223. var highestmod_1 = 0;
  2224. // Get the indexes of all of the displayed panes
  2225. var dispIndex = [];
  2226. for (var _i = 0, _a = this.s.panes; _i < _a.length; _i++) {
  2227. var pane = _a[_i];
  2228. if (pane.s.displayed) {
  2229. dispIndex.push(pane.s.index);
  2230. }
  2231. }
  2232. var displayCount = dispIndex.length;
  2233. // If the neatest number is the number we have then use this.
  2234. if (target === displayCount) {
  2235. highest_1 = target;
  2236. }
  2237. else {
  2238. // Go from the target down and find the value with the most panes left over, this will be the best fit
  2239. for (var ppr = target; ppr > 1; ppr--) {
  2240. var rem = displayCount % ppr;
  2241. if (rem === 0) {
  2242. highest_1 = ppr;
  2243. highestmod_1 = 0;
  2244. break;
  2245. }
  2246. // If there are more left over at this amount of panes per row (ppr)
  2247. // then it fits better so new values
  2248. else if (rem > highestmod_1) {
  2249. highest_1 = ppr;
  2250. highestmod_1 = rem;
  2251. }
  2252. }
  2253. }
  2254. // If there is a perfect fit then none are to be wider
  2255. var widerIndexes_1 = highestmod_1 !== 0 ? dispIndex.slice(dispIndex.length - highestmod_1, dispIndex.length) : [];
  2256. this.s.panes.forEach(function (pane) {
  2257. // Resize the pane with the new layout
  2258. if (pane.s.displayed) {
  2259. pane.resize('columns-' + (!widerIndexes_1.includes(pane.s.index) ? highest_1 : highestmod_1));
  2260. }
  2261. });
  2262. }
  2263. else {
  2264. for (var _b = 0, _c = this.s.panes; _b < _c.length; _b++) {
  2265. var pane = _c[_b];
  2266. pane.adjustTopRow();
  2267. }
  2268. }
  2269. return this;
  2270. };
  2271. /**
  2272. * Holder method that is userd in SearchPanesST to set listeners that have an effect on other panes
  2273. *
  2274. * @param isPreselect boolean to indicate if the preselect array is to override the current selection list.
  2275. */
  2276. SearchPanes.prototype._initSelectionListeners = function (isPreselect) {
  2277. return;
  2278. };
  2279. /**
  2280. * Blank method that is overridden in SearchPanesST to retrieve the totals from the server data
  2281. */
  2282. SearchPanes.prototype._serverTotals = function () {
  2283. return;
  2284. };
  2285. /**
  2286. * Set's the xhr listener so that SP can extact appropriate data from the response
  2287. */
  2288. SearchPanes.prototype._setXHR = function () {
  2289. var _this = this;
  2290. var hostSettings = this.s.dt.settings()[0];
  2291. var run = function (json) {
  2292. if (json && json.searchPanes && json.searchPanes.options) {
  2293. _this.s.serverData = json;
  2294. _this.s.serverData.tableLength = json.recordsTotal;
  2295. _this._serverTotals();
  2296. }
  2297. };
  2298. // We are using the xhr event to rebuild the panes if required due to viewTotal being enabled
  2299. // If viewTotal is not enabled then we simply update the data from the server
  2300. this.s.dt.on('xhr.dtsps', function (e, settings, json) {
  2301. if (hostSettings === settings) {
  2302. run(json);
  2303. }
  2304. });
  2305. // Account for the initial JSON fetch having already completed
  2306. run(this.s.dt.ajax.json());
  2307. };
  2308. /**
  2309. * Set's the function that is to be performed when a state is loaded
  2310. *
  2311. * Overridden by the method in SearchPanesST
  2312. */
  2313. SearchPanes.prototype._stateLoadListener = function () {
  2314. var _this = this;
  2315. this.s.dt.on('stateLoadParams.dtsps', function (e, settings, data) {
  2316. if (data.searchPanes === undefined) {
  2317. return;
  2318. }
  2319. _this.clearSelections();
  2320. // Set the selection list for the panes so that the correct
  2321. // rows can be reselected and in the right order
  2322. _this.s.selectionList =
  2323. data.searchPanes.selectionList ?
  2324. data.searchPanes.selectionList :
  2325. [];
  2326. // Find the panes that match from the state and the actual instance
  2327. if (data.searchPanes.panes) {
  2328. for (var _i = 0, _a = data.searchPanes.panes; _i < _a.length; _i++) {
  2329. var loadedPane = _a[_i];
  2330. for (var _b = 0, _c = _this.s.panes; _b < _c.length; _b++) {
  2331. var pane = _c[_b];
  2332. if (loadedPane.id === pane.s.index && pane.s.dtPane) {
  2333. // Set the value of the searchbox
  2334. pane.dom.searchBox.val(loadedPane.searchTerm);
  2335. // Set the value of the order
  2336. pane.s.dtPane.order(loadedPane.order);
  2337. }
  2338. }
  2339. }
  2340. }
  2341. _this._makeSelections(_this.s.selectionList);
  2342. });
  2343. };
  2344. /**
  2345. * Updates the selectionList when cascade is not in place
  2346. *
  2347. * Overridden in SearchPanesST
  2348. */
  2349. SearchPanes.prototype._updateSelection = function () {
  2350. this.s.selectionList = [];
  2351. for (var _i = 0, _a = this.s.panes; _i < _a.length; _i++) {
  2352. var pane = _a[_i];
  2353. if (pane.s.dtPane) {
  2354. var rows = pane.s.dtPane.rows({ selected: true }).data().toArray().map(function (el) { return el.filter; });
  2355. if (rows.length) {
  2356. this.s.selectionList.push({
  2357. column: pane.s.index,
  2358. rows: rows
  2359. });
  2360. }
  2361. }
  2362. }
  2363. };
  2364. /**
  2365. * Attach the panes, buttons and title to the document
  2366. */
  2367. SearchPanes.prototype._attach = function () {
  2368. var _this = this;
  2369. this.dom.titleRow
  2370. .removeClass(this.classes.hide)
  2371. .detach()
  2372. .append(this.dom.title);
  2373. // If the clear button is permitted attach it
  2374. if (this.c.clear) {
  2375. this.dom.clearAll
  2376. .appendTo(this.dom.titleRow)
  2377. .on('click.dtsps', function () { return _this.clearSelections(); });
  2378. }
  2379. if (this.c.collapse) {
  2380. this.dom.showAll.appendTo(this.dom.titleRow);
  2381. this.dom.collapseAll.appendTo(this.dom.titleRow);
  2382. this._setCollapseListener();
  2383. }
  2384. // Attach the container for each individual pane to the overall container
  2385. for (var _i = 0, _a = this.s.panes; _i < _a.length; _i++) {
  2386. var pane = _a[_i];
  2387. this.dom.panes.append(pane.dom.container);
  2388. }
  2389. // Attach everything to the document
  2390. this.dom.container
  2391. .text('')
  2392. .removeClass(this.classes.hide)
  2393. .append(this.dom.titleRow)
  2394. .append(this.dom.panes);
  2395. // WORKAROUND
  2396. this.s.panes.forEach(function (pane) { return pane.setListeners(); });
  2397. if ($('div.' + this.classes.container).length === 0) {
  2398. this.dom.container.prependTo(this.s.dt);
  2399. }
  2400. };
  2401. /**
  2402. * If there are no panes to display then this method is called to either
  2403. * display a message in their place or hide them completely.
  2404. */
  2405. SearchPanes.prototype._attachMessage = function () {
  2406. // Create a message to display on the screen
  2407. var message;
  2408. try {
  2409. message = this.s.dt.i18n('searchPanes.emptyPanes', this.c.i18n.emptyPanes);
  2410. }
  2411. catch (error) {
  2412. message = null;
  2413. }
  2414. // If the message is an empty string then searchPanes.emptyPanes is undefined,
  2415. // therefore the pane container should be removed from the display
  2416. if (message === null) {
  2417. this.dom.container.addClass(this.classes.hide);
  2418. this.dom.titleRow.removeClass(this.classes.hide);
  2419. return;
  2420. }
  2421. // Otherwise display the message
  2422. this.dom.container.removeClass(this.classes.hide);
  2423. this.dom.titleRow.addClass(this.classes.hide);
  2424. this.dom.emptyMessage.html(message).appendTo(this.dom.container);
  2425. };
  2426. /**
  2427. * Attaches the panes to the document and displays a message or hides if there are none
  2428. */
  2429. SearchPanes.prototype._attachPaneContainer = function () {
  2430. // If a pane is to be displayed then attach the normal pane output
  2431. for (var _i = 0, _a = this.s.panes; _i < _a.length; _i++) {
  2432. var pane = _a[_i];
  2433. if (pane.s.displayed === true) {
  2434. this._attach();
  2435. return;
  2436. }
  2437. }
  2438. // Otherwise attach the custom message or remove the container from the display
  2439. this._attachMessage();
  2440. };
  2441. /**
  2442. * Checks which panes are collapsed and then performs relevant actions to the collapse/show all buttons
  2443. */
  2444. SearchPanes.prototype._checkCollapse = function () {
  2445. var disableClose = true;
  2446. var disableShow = true;
  2447. for (var _i = 0, _a = this.s.panes; _i < _a.length; _i++) {
  2448. var pane = _a[_i];
  2449. if (pane.s.displayed) {
  2450. // If the pane is not collapsed
  2451. if (!pane.dom.collapseButton.hasClass(pane.classes.rotated)) {
  2452. // Enable the collapse all button
  2453. this.dom.collapseAll.removeClass(this.classes.disabledButton).removeAttr('disabled');
  2454. disableClose = false;
  2455. }
  2456. else {
  2457. // Otherwise enable the show all button
  2458. this.dom.showAll.removeClass(this.classes.disabledButton).removeAttr('disabled');
  2459. disableShow = false;
  2460. }
  2461. }
  2462. }
  2463. // If this flag is still true, no panes are open so the close button should be disabled
  2464. if (disableClose) {
  2465. this.dom.collapseAll.addClass(this.classes.disabledButton).attr('disabled', 'true');
  2466. }
  2467. // If this flag is still true, no panes are closed so the show button should be disabled
  2468. if (disableShow) {
  2469. this.dom.showAll.addClass(this.classes.disabledButton).attr('disabled', 'true');
  2470. }
  2471. };
  2472. /**
  2473. * Attaches the message to the document but does not add any panes
  2474. */
  2475. SearchPanes.prototype._checkMessage = function () {
  2476. // If a pane is to be displayed then attach the normal pane output
  2477. for (var _i = 0, _a = this.s.panes; _i < _a.length; _i++) {
  2478. var pane = _a[_i];
  2479. if (pane.s.displayed === true) {
  2480. // Ensure that the empty message is removed if a pane is displayed
  2481. this.dom.emptyMessage.detach();
  2482. this.dom.titleRow.removeClass(this.classes.hide);
  2483. return;
  2484. }
  2485. }
  2486. // Otherwise attach the custom message or remove the container from the display
  2487. this._attachMessage();
  2488. };
  2489. /**
  2490. * Collapses all of the panes
  2491. */
  2492. SearchPanes.prototype._collapseAll = function () {
  2493. for (var _i = 0, _a = this.s.panes; _i < _a.length; _i++) {
  2494. var pane = _a[_i];
  2495. pane.collapse();
  2496. }
  2497. };
  2498. /**
  2499. * Finds a pane based upon the name of that pane
  2500. *
  2501. * @param name string representing the name of the pane
  2502. * @returns SearchPane The pane which has that name
  2503. */
  2504. SearchPanes.prototype._findPane = function (name) {
  2505. for (var _i = 0, _a = this.s.panes; _i < _a.length; _i++) {
  2506. var pane = _a[_i];
  2507. if (name === pane.s.name) {
  2508. return pane;
  2509. }
  2510. }
  2511. };
  2512. /**
  2513. * Gets the selection list from the previous state and stores it in the selectionList Property
  2514. */
  2515. SearchPanes.prototype._getState = function () {
  2516. var loadedFilter = this.s.dt.state.loaded();
  2517. if (loadedFilter && loadedFilter.searchPanes && loadedFilter.searchPanes.selectionList) {
  2518. this.s.selectionList = loadedFilter.searchPanes.selectionList;
  2519. }
  2520. };
  2521. SearchPanes.prototype._makeSelections = function (selectList) {
  2522. for (var _i = 0, selectList_1 = selectList; _i < selectList_1.length; _i++) {
  2523. var selection = selectList_1[_i];
  2524. var pane = void 0;
  2525. for (var _a = 0, _b = this.s.panes; _a < _b.length; _a++) {
  2526. var p = _b[_a];
  2527. if (p.s.index === selection.column) {
  2528. pane = p;
  2529. break;
  2530. }
  2531. }
  2532. if (pane && pane.s.dtPane) {
  2533. for (var j = 0; j < pane.s.dtPane.rows().data().toArray().length; j++) {
  2534. if (selection.rows.includes(typeof pane.s.dtPane.row(j).data().filter === 'function' ?
  2535. pane.s.dtPane.cell(j, 0).data() :
  2536. pane.s.dtPane.row(j).data().filter)) {
  2537. pane.s.dtPane.row(j).select();
  2538. }
  2539. }
  2540. pane.updateTable();
  2541. }
  2542. }
  2543. };
  2544. /**
  2545. * Declares the instances of individual searchpanes dependant on the number of columns.
  2546. * It is necessary to run this once preInit has completed otherwise no panes will be
  2547. * created as the column count will be 0.
  2548. *
  2549. * @param table the DataTable api for the parent table
  2550. * @param paneSettings the settings passed into the constructor
  2551. * @param opts the options passed into the constructor
  2552. */
  2553. SearchPanes.prototype._paneDeclare = function (table, paneSettings, opts) {
  2554. var _this = this;
  2555. // Create Panes
  2556. table
  2557. .columns(this.c.columns.length > 0 ? this.c.columns : undefined)
  2558. .eq(0)
  2559. .each(function (idx) {
  2560. _this.s.panes.push(new _this.s.paneClass(paneSettings, opts, idx, _this.dom.panes));
  2561. });
  2562. // If there is any extra custom panes defined then create panes for them too
  2563. var colCount = table.columns().eq(0).toArray().length;
  2564. for (var i = 0; i < this.c.panes.length; i++) {
  2565. var id = colCount + i;
  2566. this.s.panes.push(new this.s.paneClass(paneSettings, opts, id, this.dom.panes, this.c.panes[i]));
  2567. }
  2568. // If a custom ordering is being used
  2569. if (this.c.order.length > 0) {
  2570. // Make a new Array of panes based upon the order
  2571. this.s.panes = this.c.order.map(function (name) { return _this._findPane(name); });
  2572. }
  2573. // If this internal property is true then the DataTable has been initialised already
  2574. if (this.s.dt.settings()[0]._bInitComplete) {
  2575. this._startup(table);
  2576. }
  2577. else {
  2578. // Otherwise add the paneStartup function to the list of functions
  2579. // that are to be run when the table is initialised. This will garauntee that the
  2580. // panes are initialised before the init event and init Complete callback is fired
  2581. this.s.dt.settings()[0].aoInitComplete.push({
  2582. fn: function () { return _this._startup(table); }
  2583. });
  2584. }
  2585. };
  2586. /**
  2587. * Sets the listeners for the collapse and show all buttons
  2588. * Also sets and performs checks on current panes to see if they are collapsed
  2589. */
  2590. SearchPanes.prototype._setCollapseListener = function () {
  2591. var _this = this;
  2592. this.dom.collapseAll.on('click.dtsps', function () {
  2593. _this._collapseAll();
  2594. _this.dom.collapseAll.addClass(_this.classes.disabledButton).attr('disabled', 'true');
  2595. _this.dom.showAll.removeClass(_this.classes.disabledButton).removeAttr('disabled');
  2596. _this.s.dt.state.save();
  2597. });
  2598. this.dom.showAll.on('click.dtsps', function () {
  2599. _this._showAll();
  2600. _this.dom.showAll.addClass(_this.classes.disabledButton).attr('disabled', 'true');
  2601. _this.dom.collapseAll.removeClass(_this.classes.disabledButton).removeAttr('disabled');
  2602. _this.s.dt.state.save();
  2603. });
  2604. for (var _i = 0, _a = this.s.panes; _i < _a.length; _i++) {
  2605. var pane = _a[_i];
  2606. // We want to make the same check whenever there is a collapse/expand
  2607. pane.dom.collapseButton.on('click.dtsps', function () { return _this._checkCollapse(); });
  2608. }
  2609. this._checkCollapse();
  2610. };
  2611. /**
  2612. * Shows all of the panes
  2613. */
  2614. SearchPanes.prototype._showAll = function () {
  2615. for (var _i = 0, _a = this.s.panes; _i < _a.length; _i++) {
  2616. var pane = _a[_i];
  2617. pane.show();
  2618. }
  2619. };
  2620. /**
  2621. * Initialises the tables previous/preset selections and initialises callbacks for events
  2622. *
  2623. * @param table the parent table for which the searchPanes are being created
  2624. */
  2625. SearchPanes.prototype._startup = function (table) {
  2626. var _this = this;
  2627. // Attach clear button and title bar to the document
  2628. this._attach();
  2629. this.dom.panes.empty();
  2630. for (var _i = 0, _a = this.s.panes; _i < _a.length; _i++) {
  2631. var pane = _a[_i];
  2632. pane.rebuildPane(Object.keys(this.s.serverData).length > 0 ? this.s.serverData : undefined);
  2633. this.dom.panes.append(pane.dom.container);
  2634. }
  2635. // If the layout is set to auto then the panes need to be resized to their best fit
  2636. if (this.c.layout === 'auto') {
  2637. this.resizePanes();
  2638. }
  2639. var loadedFilter = this.s.dt.state.loaded();
  2640. // Reset the paging if that has been saved in the state
  2641. if (!this.s.stateRead && loadedFilter) {
  2642. this.s.dt
  2643. .page(loadedFilter.start / this.s.dt.page.len())
  2644. .draw('page');
  2645. }
  2646. this.s.stateRead = true;
  2647. this._checkMessage();
  2648. // When a draw is called on the DataTable, update all of the panes incase the data in the DataTable has changed
  2649. table.on('preDraw.dtsps', function () {
  2650. // Check that the panes are not updating to avoid infinite loops
  2651. // Also check that this draw is not due to paging
  2652. if (!_this.s.updating && !_this.s.paging) {
  2653. _this._updateFilterCount();
  2654. _this._updateSelection();
  2655. }
  2656. // Paging flag reset - we only need to dodge the draw once
  2657. _this.s.paging = false;
  2658. });
  2659. $(window).on('resize.dtsps', dataTable.util.throttle(function () { return _this.resizePanes(); }));
  2660. // Whenever a state save occurs store the selection list in the state object
  2661. this.s.dt.on('stateSaveParams.dtsps', function (e, settings, data) {
  2662. if (data.searchPanes === undefined) {
  2663. data.searchPanes = {};
  2664. }
  2665. data.searchPanes.selectionList = _this.s.selectionList;
  2666. });
  2667. this._stateLoadListener();
  2668. // Listener for paging on main table
  2669. table.off('page.dtsps page-nc.dtsps').on('page.dtsps page-nc.dtsps', function (e, s) {
  2670. _this.s.paging = true;
  2671. // This is an indicator to any selection tracking classes that paging has occured
  2672. // It has to happen here so that we don't stack event listeners unnecessarily
  2673. // The value is only ever set back to false in the SearchPanesST class
  2674. // Equally it is never read in this class
  2675. _this.s.pagingST = true;
  2676. _this.s.page = _this.s.dt.page();
  2677. });
  2678. if (this.s.dt.page.info().serverSide) {
  2679. table.off('preXhr.dtsps').on('preXhr.dtsps', function (e, settings, data) {
  2680. if (!data.searchPanes) {
  2681. data.searchPanes = {};
  2682. }
  2683. if (!data.searchPanes_null) {
  2684. data.searchPanes_null = {};
  2685. }
  2686. // Count how many filters are being applied
  2687. var filterCount = 0;
  2688. for (var _i = 0, _a = _this.s.panes; _i < _a.length; _i++) {
  2689. var pane = _a[_i];
  2690. var src = _this.s.dt.column(pane.s.index).dataSrc();
  2691. if (!data.searchPanes[src]) {
  2692. data.searchPanes[src] = {};
  2693. }
  2694. if (!data.searchPanes_null[src]) {
  2695. data.searchPanes_null[src] = {};
  2696. }
  2697. if (pane.s.dtPane) {
  2698. var rowData = pane.s.dtPane.rows({ selected: true }).data().toArray();
  2699. for (var i = 0; i < rowData.length; i++) {
  2700. data.searchPanes[src][i] = rowData[i].filter;
  2701. if (!data.searchPanes[src][i]) {
  2702. data.searchPanes_null[src][i] = true;
  2703. }
  2704. filterCount++;
  2705. }
  2706. }
  2707. }
  2708. // If there is a filter to be applied, then we need to read from the start of the result set
  2709. // and set the paging to 0. This matches the behaviour of client side processing
  2710. if (filterCount > 0) {
  2711. // If the number of filters has changed we need to read from the start of the
  2712. // result set and reset the paging
  2713. if (filterCount !== _this.s.filterCount) {
  2714. data.start = 0;
  2715. _this.s.page = 0;
  2716. }
  2717. // Otherwise it is a paging request and we need to read from whatever the paging has been set to
  2718. else {
  2719. data.start = _this.s.page * _this.s.dt.page.len();
  2720. }
  2721. _this.s.dt.page(_this.s.page);
  2722. _this.s.filterCount = filterCount;
  2723. }
  2724. if (_this.s.selectionList.length > 0) {
  2725. data.searchPanesLast = _this.s.dt
  2726. .column(_this.s.selectionList[_this.s.selectionList.length - 1].column)
  2727. .dataSrc();
  2728. }
  2729. });
  2730. }
  2731. else {
  2732. table.on('preXhr.dtsps', function () { return _this.s.panes.forEach(function (pane) { return pane.clearData(); }); });
  2733. }
  2734. // If the data is reloaded from the server then it is possible that it has changed completely,
  2735. // so we need to rebuild the panes
  2736. this.s.dt.on('xhr.dtsps', function (e, settings) {
  2737. if (settings.nTable !== _this.s.dt.table().node()) {
  2738. return;
  2739. }
  2740. if (!_this.s.dt.page.info().serverSide) {
  2741. var processing_1 = false;
  2742. _this.s.dt.one('preDraw.dtsps', function () {
  2743. if (processing_1) {
  2744. return;
  2745. }
  2746. var page = _this.s.dt.page();
  2747. processing_1 = true;
  2748. _this.s.updating = true;
  2749. _this.dom.panes.empty();
  2750. for (var _i = 0, _a = _this.s.panes; _i < _a.length; _i++) {
  2751. var pane = _a[_i];
  2752. pane.clearData(); // Clears all of the bins and will mean that the data has to be re-read
  2753. // Pass a boolean to say whether this is the last choice made for maintaining selections
  2754. // when rebuilding
  2755. pane.rebuildPane(undefined, true);
  2756. _this.dom.panes.append(pane.dom.container);
  2757. }
  2758. if (!_this.s.dt.page.info().serverSide) {
  2759. _this.s.dt.draw();
  2760. }
  2761. _this.s.updating = false;
  2762. _this._updateSelection();
  2763. _this._checkMessage();
  2764. _this.s.dt.one('draw.dtsps', function () {
  2765. _this.s.updating = true;
  2766. _this.s.dt.page(page).draw(false);
  2767. _this.s.updating = false;
  2768. });
  2769. });
  2770. }
  2771. });
  2772. // PreSelect any selections which have been defined using the preSelect option
  2773. var selectList = this.c.preSelect;
  2774. if (loadedFilter && loadedFilter.searchPanes && loadedFilter.searchPanes.selectionList) {
  2775. selectList = loadedFilter.searchPanes.selectionList;
  2776. }
  2777. this._makeSelections(selectList);
  2778. // Update the title bar to show how many filters have been selected
  2779. this._updateFilterCount();
  2780. // If the table is destroyed and restarted then clear the selections so that they do not persist.
  2781. table.on('destroy.dtsps', function () {
  2782. for (var _i = 0, _a = _this.s.panes; _i < _a.length; _i++) {
  2783. var pane = _a[_i];
  2784. pane.destroy();
  2785. }
  2786. table.off('.dtsps');
  2787. _this.dom.showAll.off('.dtsps');
  2788. _this.dom.clearAll.off('.dtsps');
  2789. _this.dom.collapseAll.off('.dtsps');
  2790. $(table.table().node()).off('.dtsps');
  2791. _this.dom.container.detach();
  2792. _this.clearSelections();
  2793. });
  2794. if (this.c.collapse) {
  2795. this._setCollapseListener();
  2796. }
  2797. // When the clear All button has been pressed clear all of the selections in the panes
  2798. if (this.c.clear) {
  2799. this.dom.clearAll.on('click.dtsps', function () { return _this.clearSelections(); });
  2800. }
  2801. table.settings()[0]._searchPanes = this;
  2802. // This state save is required so that state is maintained over multiple refreshes if no actions are made
  2803. this.s.dt.state.save();
  2804. };
  2805. /**
  2806. * Updates the number of filters that have been applied in the title
  2807. */
  2808. SearchPanes.prototype._updateFilterCount = function () {
  2809. var filterCount = 0;
  2810. // Add the number of all of the filters throughout the panes
  2811. for (var _i = 0, _a = this.s.panes; _i < _a.length; _i++) {
  2812. var pane = _a[_i];
  2813. if (pane.s.dtPane) {
  2814. filterCount += pane.getPaneCount();
  2815. }
  2816. }
  2817. // Run the message through the internationalisation method to improve readability
  2818. this.dom.title.html(this.s.dt.i18n('searchPanes.title', this.c.i18n.title, filterCount));
  2819. if (this.c.filterChanged && typeof this.c.filterChanged === 'function') {
  2820. this.c.filterChanged.call(this.s.dt, filterCount);
  2821. }
  2822. if (filterCount === 0) {
  2823. this.dom.clearAll.addClass(this.classes.disabledButton).attr('disabled', 'true');
  2824. }
  2825. else {
  2826. this.dom.clearAll.removeClass(this.classes.disabledButton).removeAttr('disabled');
  2827. }
  2828. };
  2829. SearchPanes.version = '2.0.2';
  2830. SearchPanes.classes = {
  2831. clear: 'dtsp-clear',
  2832. clearAll: 'dtsp-clearAll',
  2833. collapseAll: 'dtsp-collapseAll',
  2834. container: 'dtsp-searchPanes',
  2835. disabledButton: 'dtsp-disabledButton',
  2836. emptyMessage: 'dtsp-emptyMessage',
  2837. hide: 'dtsp-hidden',
  2838. panes: 'dtsp-panesContainer',
  2839. search: 'dtsp-search',
  2840. showAll: 'dtsp-showAll',
  2841. title: 'dtsp-title',
  2842. titleRow: 'dtsp-titleRow'
  2843. };
  2844. // Define SearchPanes default options
  2845. SearchPanes.defaults = {
  2846. clear: true,
  2847. collapse: true,
  2848. columns: [],
  2849. container: function (dt) {
  2850. return dt.table().container();
  2851. },
  2852. filterChanged: undefined,
  2853. i18n: {
  2854. clearMessage: 'Clear All',
  2855. clearPane: '&times;',
  2856. collapse: {
  2857. 0: 'SearchPanes',
  2858. _: 'SearchPanes (%d)'
  2859. },
  2860. collapseMessage: 'Collapse All',
  2861. count: '{total}',
  2862. emptyMessage: '<em>No data</em>',
  2863. emptyPanes: 'No SearchPanes',
  2864. loadMessage: 'Loading Search Panes...',
  2865. showMessage: 'Show All',
  2866. title: 'Filters Active - %d'
  2867. },
  2868. layout: 'auto',
  2869. order: [],
  2870. panes: [],
  2871. preSelect: []
  2872. };
  2873. return SearchPanes;
  2874. }());
  2875. var __extends = (window && window.__extends) || (function () {
  2876. var extendStatics = function (d, b) {
  2877. extendStatics = Object.setPrototypeOf ||
  2878. ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
  2879. function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
  2880. return extendStatics(d, b);
  2881. };
  2882. return function (d, b) {
  2883. extendStatics(d, b);
  2884. function __() { this.constructor = d; }
  2885. d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
  2886. };
  2887. })();
  2888. var SearchPanesST = /** @class */ (function (_super) {
  2889. __extends(SearchPanesST, _super);
  2890. function SearchPanesST(paneSettings, opts, fromPreInit) {
  2891. if (fromPreInit === void 0) { fromPreInit = false; }
  2892. var _this = this;
  2893. var paneClass;
  2894. if (opts.cascadePanes && opts.viewTotal) {
  2895. paneClass = SearchPaneCascadeViewTotal;
  2896. }
  2897. else if (opts.cascadePanes) {
  2898. paneClass = SearchPaneCascade;
  2899. }
  2900. else if (opts.viewTotal) {
  2901. paneClass = SearchPaneViewTotal;
  2902. }
  2903. _this = _super.call(this, paneSettings, opts, fromPreInit, paneClass) || this;
  2904. var loadedFilter = _this.s.dt.state.loaded();
  2905. var loadFn = function () { return _this._initSelectionListeners(true, loadedFilter && loadedFilter.searchPanes && loadedFilter.searchPanes.selectionList ?
  2906. loadedFilter.searchPanes.selectionList :
  2907. _this.c.preSelect); };
  2908. _this.s.dt.off('init.dtsps').on('init.dtsps', loadFn);
  2909. return _this;
  2910. }
  2911. /**
  2912. * Ensures that the correct selection listeners are set for selection tracking
  2913. *
  2914. * @param preSelect Any values that are to be preselected
  2915. */
  2916. SearchPanesST.prototype._initSelectionListeners = function (isPreselect, preSelect) {
  2917. if (isPreselect === void 0) { isPreselect = true; }
  2918. if (preSelect === void 0) { preSelect = []; }
  2919. if (isPreselect) {
  2920. this.s.selectionList = preSelect;
  2921. }
  2922. // Set selection listeners for each pane
  2923. for (var _i = 0, _a = this.s.panes; _i < _a.length; _i++) {
  2924. var pane = _a[_i];
  2925. if (pane.s.displayed) {
  2926. pane.s.dtPane
  2927. .off('select.dtsp')
  2928. .on('select.dtsp', this._update(pane))
  2929. .off('deselect.dtsp')
  2930. .on('deselect.dtsp', this._updateTimeout(pane));
  2931. }
  2932. }
  2933. // Update on every draw
  2934. this.s.dt.off('draw.dtsps').on('draw.dtsps', this._update());
  2935. // Also update right now as table has just initialised
  2936. this._updateSelectionList();
  2937. };
  2938. /**
  2939. * Retrieve the total values from the server data
  2940. */
  2941. SearchPanesST.prototype._serverTotals = function () {
  2942. for (var _i = 0, _a = this.s.panes; _i < _a.length; _i++) {
  2943. var pane = _a[_i];
  2944. if (pane.s.colOpts.show) {
  2945. var colTitle = this.s.dt.column(pane.s.index).dataSrc();
  2946. var blockVT = true;
  2947. // If any of the counts are not equal to the totals filtering must be active
  2948. if (this.s.serverData.searchPanes.options[colTitle]) {
  2949. for (var _b = 0, _c = this.s.serverData.searchPanes.options[colTitle]; _b < _c.length; _b++) {
  2950. var data = _c[_b];
  2951. if (data.total !== data.count) {
  2952. blockVT = false;
  2953. break;
  2954. }
  2955. }
  2956. }
  2957. // Set if filtering is present on the pane and populate the data arrays
  2958. pane.s.filteringActive = !blockVT;
  2959. pane._serverPopulate(this.s.serverData);
  2960. }
  2961. }
  2962. };
  2963. /**
  2964. * Set's the function that is to be performed when a state is loaded
  2965. *
  2966. * Overrides the method in SearchPanes
  2967. */
  2968. SearchPanesST.prototype._stateLoadListener = function () {
  2969. var _this = this;
  2970. var stateLoadFunction = function (e, settings, data) {
  2971. if (data.searchPanes === undefined) {
  2972. return;
  2973. }
  2974. // Set the selection list for the panes so that the correct
  2975. // rows can be reselected and in the right order
  2976. _this.s.selectionList =
  2977. data.searchPanes.selectionList ?
  2978. data.searchPanes.selectionList :
  2979. [];
  2980. // Find the panes that match from the state and the actual instance
  2981. if (data.searchPanes.panes) {
  2982. for (var _i = 0, _a = data.searchPanes.panes; _i < _a.length; _i++) {
  2983. var loadedPane = _a[_i];
  2984. for (var _b = 0, _c = _this.s.panes; _b < _c.length; _b++) {
  2985. var pane = _c[_b];
  2986. if (loadedPane.id === pane.s.index && pane.s.dtPane) {
  2987. // Set the value of the searchbox
  2988. pane.dom.searchBox.val(loadedPane.searchTerm);
  2989. // Set the value of the order
  2990. pane.s.dtPane.order(loadedPane.order);
  2991. }
  2992. }
  2993. }
  2994. }
  2995. _this._updateSelectionList();
  2996. };
  2997. this.s.dt.off('stateLoadParams.dtsps', stateLoadFunction).on('stateLoadParams.dtsps', stateLoadFunction);
  2998. };
  2999. /**
  3000. * Remove the function's actions when using cascade
  3001. *
  3002. * Overrides the method in SearchPanes
  3003. */
  3004. SearchPanesST.prototype._updateSelection = function () {
  3005. return;
  3006. };
  3007. /**
  3008. * Returns a function that updates the selection list based on a specific pane
  3009. * Also clears the timeout to stop the deselect from running
  3010. *
  3011. * @param pane the pane that is to have it's selections loaded
  3012. */
  3013. SearchPanesST.prototype._update = function (pane) {
  3014. var _this = this;
  3015. if (pane === void 0) { pane = undefined; }
  3016. return function () {
  3017. if (pane) {
  3018. clearTimeout(pane.s.deselectTimeout);
  3019. }
  3020. _this._updateSelectionList(pane);
  3021. };
  3022. };
  3023. /**
  3024. * Returns a function that updates the selection list based on a specific pane
  3025. * Also sets a timeout incase a select is about to be made
  3026. *
  3027. * @param pane the pane that is to have it's selections loaded
  3028. */
  3029. SearchPanesST.prototype._updateTimeout = function (pane) {
  3030. var _this = this;
  3031. if (pane === void 0) { pane = undefined; }
  3032. return function () { return pane ?
  3033. pane.s.deselectTimeout = setTimeout(function () { return _this._updateSelectionList(pane); }, 50) :
  3034. _this._updateSelectionList(); };
  3035. };
  3036. /**
  3037. * Updates the selection list to include the latest selections for a given pane
  3038. *
  3039. * @param index The index of the pane that is to be updated
  3040. * @param selected Which rows are selected within the pane
  3041. */
  3042. SearchPanesST.prototype._updateSelectionList = function (paneIn) {
  3043. if (paneIn === void 0) { paneIn = undefined; }
  3044. // Bail if any of these flags are set
  3045. if (this.s.pagingST) {
  3046. // Reset pagingST flag
  3047. this.s.pagingST = false;
  3048. return;
  3049. }
  3050. else if (this.s.updating || paneIn && paneIn.s.serverSelecting) {
  3051. return;
  3052. }
  3053. if (paneIn !== undefined) {
  3054. if (this.s.dt.page.info().serverSide) {
  3055. paneIn._updateSelection();
  3056. }
  3057. // Get filter values for all of the rows and the selections
  3058. var rows = paneIn.s.dtPane.rows({ selected: true }).data().toArray().map(function (el) { return el.filter; });
  3059. this.s.selectionList = this.s.selectionList.filter(function (selection) { return selection.column !== paneIn.s.index; });
  3060. if (rows.length > 0) {
  3061. this.s.selectionList.push({
  3062. column: paneIn.s.index,
  3063. rows: rows
  3064. });
  3065. paneIn.dom.clear.removeClass(this.classes.disabledButton).removeAttr('disabled');
  3066. }
  3067. else {
  3068. paneIn.dom.clear.addClass(this.classes.disabledButton).attr('disabled', 'true');
  3069. }
  3070. if (this.s.dt.page.info().serverSide) {
  3071. this.s.dt.draw(false);
  3072. }
  3073. }
  3074. this._remakeSelections();
  3075. this._updateFilterCount();
  3076. };
  3077. /**
  3078. * Remake the selections that were present before new data or calculations have occured
  3079. */
  3080. SearchPanesST.prototype._remakeSelections = function () {
  3081. this.s.updating = true;
  3082. if (!this.s.dt.page.info().serverSide) {
  3083. var tmpSL = this.s.selectionList;
  3084. var anotherFilter = false;
  3085. this.clearSelections();
  3086. this.s.dt.draw();
  3087. // When there are no selections present if the length of the data does not match the searched data
  3088. // then another filter is present
  3089. if (this.s.dt.rows().toArray()[0].length > this.s.dt.rows({ search: 'applied' }).toArray()[0].length) {
  3090. anotherFilter = true;
  3091. }
  3092. this.s.selectionList = tmpSL;
  3093. // Update the rows in each pane
  3094. for (var _i = 0, _a = this.s.panes; _i < _a.length; _i++) {
  3095. var pane = _a[_i];
  3096. if (pane.s.displayed) {
  3097. pane.s.filteringActive = anotherFilter;
  3098. pane.updateRows();
  3099. }
  3100. }
  3101. for (var _b = 0, _c = this.s.selectionList; _b < _c.length; _b++) {
  3102. var selection = _c[_b];
  3103. var pane = void 0;
  3104. for (var _d = 0, _e = this.s.panes; _d < _e.length; _d++) {
  3105. var paneCheck = _e[_d];
  3106. if (paneCheck.s.index === selection.column) {
  3107. pane = paneCheck;
  3108. break;
  3109. }
  3110. }
  3111. if (!pane.s.dtPane) {
  3112. continue;
  3113. }
  3114. var ids = pane.s.dtPane.rows().indexes().toArray();
  3115. // Select the rows that are present in the selection list
  3116. for (var i = 0; i < selection.rows.length; i++) {
  3117. var rowFound = false;
  3118. for (var _f = 0, ids_1 = ids; _f < ids_1.length; _f++) {
  3119. var id = ids_1[_f];
  3120. var currRow = pane.s.dtPane.row(id);
  3121. var data = currRow.data();
  3122. if (selection.rows[i] === data.filter) {
  3123. currRow.select();
  3124. rowFound = true;
  3125. }
  3126. }
  3127. if (!rowFound) {
  3128. selection.rows.splice(i, 1);
  3129. i--;
  3130. }
  3131. }
  3132. pane.s.selections = selection.rows;
  3133. // If there are no rows selected then don't bother continuing past here
  3134. // Will just increase processing time and skew the rows that are shown in the table
  3135. if (selection.rows.length === 0) {
  3136. continue;
  3137. }
  3138. // Update the table to display the current results
  3139. this.s.dt.draw();
  3140. var filteringActive = false;
  3141. var filterCount = 0;
  3142. var prevSelectedPanes = 0;
  3143. var selectedPanes = 0;
  3144. // Add the number of all of the filters throughout the panes
  3145. for (var _g = 0, _h = this.s.panes; _g < _h.length; _g++) {
  3146. var currPane = _h[_g];
  3147. if (currPane.s.dtPane) {
  3148. filterCount += currPane.getPaneCount();
  3149. if (filterCount > prevSelectedPanes) {
  3150. selectedPanes++;
  3151. prevSelectedPanes = filterCount;
  3152. }
  3153. }
  3154. }
  3155. filteringActive = filterCount > 0;
  3156. for (var _j = 0, _k = this.s.panes; _j < _k.length; _j++) {
  3157. var currPane = _k[_j];
  3158. if (currPane.s.displayed) {
  3159. // Set the filtering active flag
  3160. if (anotherFilter || pane.s.index !== currPane.s.index || !filteringActive) {
  3161. currPane.s.filteringActive = filteringActive || anotherFilter;
  3162. }
  3163. else if (selectedPanes === 1) {
  3164. currPane.s.filteringActive = false;
  3165. }
  3166. // Update the rows to show correct counts
  3167. if (currPane.s.index !== pane.s.index) {
  3168. currPane.updateRows();
  3169. }
  3170. }
  3171. }
  3172. }
  3173. // Update table to show final search results
  3174. this.s.dt.draw();
  3175. }
  3176. else {
  3177. // Identify the last pane to have a change in selection
  3178. var pane = void 0;
  3179. if (this.s.selectionList.length > 0) {
  3180. pane = this.s.panes[this.s.selectionList[this.s.selectionList.length - 1].column];
  3181. }
  3182. // Update the rows of all of the other panes
  3183. for (var _l = 0, _m = this.s.panes; _l < _m.length; _l++) {
  3184. var currPane = _m[_l];
  3185. if (currPane.s.displayed && (!pane || currPane.s.index !== pane.s.index)) {
  3186. currPane.updateRows();
  3187. }
  3188. }
  3189. }
  3190. this.s.updating = false;
  3191. };
  3192. return SearchPanesST;
  3193. }(SearchPanes));
  3194. /*! SearchPanes 2.0.2
  3195. * 2019-2022 SpryMedia Ltd - datatables.net/license
  3196. */
  3197. // DataTables extensions common UMD. Note that this allows for AMD, CommonJS
  3198. // (with window and jQuery being allowed as parameters to the returned
  3199. // function) or just default browser loading.
  3200. (function (factory) {
  3201. if (typeof define === 'function' && define.amd) {
  3202. // AMD
  3203. define(['jquery', 'datatables.net'], function ($) {
  3204. return factory($, window, document);
  3205. });
  3206. }
  3207. else if (typeof exports === 'object') {
  3208. // CommonJS
  3209. module.exports = function (root, $) {
  3210. if (!root) {
  3211. root = window;
  3212. }
  3213. if (!$ || !$.fn.dataTable) {
  3214. // eslint-disable-next-line @typescript-eslint/no-var-requires
  3215. $ = require('datatables.net')(root, $).$;
  3216. }
  3217. return factory($, root, root.document);
  3218. };
  3219. }
  3220. else {
  3221. // Browser - assume jQuery has already been loaded
  3222. // eslint-disable-next-line no-extra-parens
  3223. factory(window.jQuery, window, document);
  3224. }
  3225. }(function ($, window, document) {
  3226. setJQuery$4($);
  3227. setJQuery($);
  3228. setJQuery$3($);
  3229. setJQuery$2($);
  3230. setJQuery$1($);
  3231. var dataTable = $.fn.dataTable;
  3232. // eslint-disable-next-line no-extra-parens
  3233. $.fn.dataTable.SearchPanes = SearchPanes;
  3234. // eslint-disable-next-line no-extra-parens
  3235. $.fn.DataTable.SearchPanes = SearchPanes;
  3236. // eslint-disable-next-line no-extra-parens
  3237. $.fn.dataTable.SearchPanesST = SearchPanesST;
  3238. // eslint-disable-next-line no-extra-parens
  3239. $.fn.DataTable.SearchPanesST = SearchPanesST;
  3240. // eslint-disable-next-line no-extra-parens
  3241. $.fn.dataTable.SearchPane = SearchPane;
  3242. // eslint-disable-next-line no-extra-parens
  3243. $.fn.DataTable.SearchPane = SearchPane;
  3244. // eslint-disable-next-line no-extra-parens
  3245. $.fn.dataTable.SearchPaneViewTotal = SearchPaneViewTotal;
  3246. // eslint-disable-next-line no-extra-parens
  3247. $.fn.DataTable.SearchPaneViewTotal = SearchPaneViewTotal;
  3248. // eslint-disable-next-line no-extra-parens
  3249. $.fn.dataTable.SearchPaneCascade = SearchPaneCascade;
  3250. // eslint-disable-next-line no-extra-parens
  3251. $.fn.DataTable.SearchPaneCascade = SearchPaneCascade;
  3252. // eslint-disable-next-line no-extra-parens
  3253. $.fn.dataTable.SearchPaneCascadeViewTotal = SearchPaneCascadeViewTotal;
  3254. // eslint-disable-next-line no-extra-parens
  3255. $.fn.DataTable.SearchPaneCascadeViewTotal = SearchPaneCascadeViewTotal;
  3256. // eslint-disable-next-line no-extra-parens
  3257. var apiRegister = $.fn.dataTable.Api.register;
  3258. apiRegister('searchPanes()', function () {
  3259. return this;
  3260. });
  3261. apiRegister('searchPanes.clearSelections()', function () {
  3262. return this.iterator('table', function (ctx) {
  3263. if (ctx._searchPanes) {
  3264. ctx._searchPanes.clearSelections();
  3265. }
  3266. });
  3267. });
  3268. apiRegister('searchPanes.rebuildPane()', function (targetIdx, maintainSelections) {
  3269. return this.iterator('table', function (ctx) {
  3270. if (ctx._searchPanes) {
  3271. ctx._searchPanes.rebuild(targetIdx, maintainSelections);
  3272. }
  3273. });
  3274. });
  3275. apiRegister('searchPanes.resizePanes()', function () {
  3276. var ctx = this.context[0];
  3277. return ctx._searchPanes ?
  3278. ctx._searchPanes.resizePanes() :
  3279. null;
  3280. });
  3281. apiRegister('searchPanes.container()', function () {
  3282. var ctx = this.context[0];
  3283. return ctx._searchPanes
  3284. ? ctx._searchPanes.getNode()
  3285. : null;
  3286. });
  3287. $.fn.dataTable.ext.buttons.searchPanesClear = {
  3288. action: function (e, dt) {
  3289. dt.searchPanes.clearSelections();
  3290. },
  3291. text: 'Clear Panes'
  3292. };
  3293. $.fn.dataTable.ext.buttons.searchPanes = {
  3294. action: function (e, dt, node, config) {
  3295. this.popover(config._panes.getNode(), {
  3296. align: 'container',
  3297. span: 'container'
  3298. });
  3299. config._panes.rebuild(undefined, true);
  3300. },
  3301. config: {},
  3302. init: function (dt, node, config) {
  3303. var buttonOpts = $.extend({
  3304. filterChanged: function (count) {
  3305. dt.button(node).text(dt.i18n('searchPanes.collapse', dt.context[0].oLanguage.searchPanes !== undefined ?
  3306. dt.context[0].oLanguage.searchPanes.collapse :
  3307. dt.context[0]._searchPanes.c.i18n.collapse, count));
  3308. }
  3309. }, config.config);
  3310. var panes = buttonOpts && (buttonOpts.cascadePanes || buttonOpts.viewTotal) ?
  3311. new $.fn.dataTable.SearchPanesST(dt, buttonOpts) :
  3312. new $.fn.dataTable.SearchPanes(dt, buttonOpts);
  3313. dt.button(node).text(config.text || dt.i18n('searchPanes.collapse', panes.c.i18n.collapse, 0));
  3314. config._panes = panes;
  3315. },
  3316. text: null
  3317. };
  3318. function _init(settings, options, fromPre) {
  3319. if (options === void 0) { options = null; }
  3320. if (fromPre === void 0) { fromPre = false; }
  3321. var api = new dataTable.Api(settings);
  3322. var opts = options
  3323. ? options
  3324. : api.init().searchPanes || dataTable.defaults.searchPanes;
  3325. var searchPanes = opts && (opts.cascadePanes || opts.viewTotal) ?
  3326. new SearchPanesST(api, opts, fromPre) :
  3327. new SearchPanes(api, opts, fromPre);
  3328. var node = searchPanes.getNode();
  3329. return node;
  3330. }
  3331. // Attach a listener to the document which listens for DataTables initialisation
  3332. // events so we can automatically initialise
  3333. $(document).on('preInit.dt.dtsp', function (e, settings) {
  3334. if (e.namespace !== 'dt') {
  3335. return;
  3336. }
  3337. if (settings.oInit.searchPanes ||
  3338. dataTable.defaults.searchPanes) {
  3339. if (!settings._searchPanes) {
  3340. _init(settings, null, true);
  3341. }
  3342. }
  3343. });
  3344. // DataTables `dom` feature option
  3345. dataTable.ext.feature.push({
  3346. cFeature: 'P',
  3347. fnInit: _init
  3348. });
  3349. // DataTables 2 layout feature
  3350. if (dataTable.ext.features) {
  3351. dataTable.ext.features.register('searchPanes', _init);
  3352. }
  3353. }));
  3354. })();