dataTables.responsive.js 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873
  1. /*! Responsive 1.0.6
  2. * 2014-2015 SpryMedia Ltd - datatables.net/license
  3. */
  4. /**
  5. * @summary Responsive
  6. * @description Responsive tables plug-in for DataTables
  7. * @version 1.0.6
  8. * @file dataTables.responsive.js
  9. * @author SpryMedia Ltd (www.sprymedia.co.uk)
  10. * @contact www.sprymedia.co.uk/contact
  11. * @copyright Copyright 2014-2015 SpryMedia Ltd.
  12. *
  13. * This source file is free software, available under the following license:
  14. * MIT license - http://datatables.net/license/mit
  15. *
  16. * This source file is distributed in the hope that it will be useful, but
  17. * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  18. * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
  19. *
  20. * For details please refer to: http://www.datatables.net
  21. */
  22. (function(window, document, undefined) {
  23. var factory = function( $, DataTable ) {
  24. "use strict";
  25. /**
  26. * Responsive is a plug-in for the DataTables library that makes use of
  27. * DataTables' ability to change the visibility of columns, changing the
  28. * visibility of columns so the displayed columns fit into the table container.
  29. * The end result is that complex tables will be dynamically adjusted to fit
  30. * into the viewport, be it on a desktop, tablet or mobile browser.
  31. *
  32. * Responsive for DataTables has two modes of operation, which can used
  33. * individually or combined:
  34. *
  35. * * Class name based control - columns assigned class names that match the
  36. * breakpoint logic can be shown / hidden as required for each breakpoint.
  37. * * Automatic control - columns are automatically hidden when there is no
  38. * room left to display them. Columns removed from the right.
  39. *
  40. * In additional to column visibility control, Responsive also has built into
  41. * options to use DataTables' child row display to show / hide the information
  42. * from the table that has been hidden. There are also two modes of operation
  43. * for this child row display:
  44. *
  45. * * Inline - when the control element that the user can use to show / hide
  46. * child rows is displayed inside the first column of the table.
  47. * * Column - where a whole column is dedicated to be the show / hide control.
  48. *
  49. * Initialisation of Responsive is performed by:
  50. *
  51. * * Adding the class `responsive` or `dt-responsive` to the table. In this case
  52. * Responsive will automatically be initialised with the default configuration
  53. * options when the DataTable is created.
  54. * * Using the `responsive` option in the DataTables configuration options. This
  55. * can also be used to specify the configuration options, or simply set to
  56. * `true` to use the defaults.
  57. *
  58. * @class
  59. * @param {object} settings DataTables settings object for the host table
  60. * @param {object} [opts] Configuration options
  61. * @requires jQuery 1.7+
  62. * @requires DataTables 1.10.1+
  63. *
  64. * @example
  65. * $('#example').DataTable( {
  66. * responsive: true
  67. * } );
  68. * } );
  69. */
  70. var Responsive = function ( settings, opts ) {
  71. // Sanity check that we are using DataTables 1.10 or newer
  72. if ( ! DataTable.versionCheck || ! DataTable.versionCheck( '1.10.1' ) ) {
  73. throw 'DataTables Responsive requires DataTables 1.10.1 or newer';
  74. }
  75. this.s = {
  76. dt: new DataTable.Api( settings ),
  77. columns: []
  78. };
  79. // Check if responsive has already been initialised on this table
  80. if ( this.s.dt.settings()[0].responsive ) {
  81. return;
  82. }
  83. // details is an object, but for simplicity the user can give it as a string
  84. if ( opts && typeof opts.details === 'string' ) {
  85. opts.details = { type: opts.details };
  86. }
  87. this.c = $.extend( true, {}, Responsive.defaults, DataTable.defaults.responsive, opts );
  88. settings.responsive = this;
  89. this._constructor();
  90. };
  91. Responsive.prototype = {
  92. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  93. * Constructor
  94. */
  95. /**
  96. * Initialise the Responsive instance
  97. *
  98. * @private
  99. */
  100. _constructor: function ()
  101. {
  102. var that = this;
  103. var dt = this.s.dt;
  104. dt.settings()[0]._responsive = this;
  105. // Use DataTables' private throttle function to avoid processor thrashing
  106. $(window).on( 'resize.dtr orientationchange.dtr', dt.settings()[0].oApi._fnThrottle( function () {
  107. that._resize();
  108. } ) );
  109. // Destroy event handler
  110. dt.on( 'destroy.dtr', function () {
  111. $(window).off( 'resize.dtr orientationchange.dtr draw.dtr' );
  112. } );
  113. // Reorder the breakpoints array here in case they have been added out
  114. // of order
  115. this.c.breakpoints.sort( function (a, b) {
  116. return a.width < b.width ? 1 :
  117. a.width > b.width ? -1 : 0;
  118. } );
  119. // Determine which columns are already hidden, and should therefore
  120. // remain hidden. todo - should this be done? See thread 22677
  121. //
  122. // this.s.alwaysHidden = dt.columns(':hidden').indexes();
  123. this._classLogic();
  124. this._resizeAuto();
  125. // Details handler
  126. var details = this.c.details;
  127. if ( details.type ) {
  128. that._detailsInit();
  129. this._detailsVis();
  130. dt.on( 'column-visibility.dtr', function () {
  131. that._detailsVis();
  132. } );
  133. // Redraw the details box on each draw. This is used until
  134. // DataTables implements a native `updated` event for rows
  135. dt.on( 'draw.dtr', function () {
  136. dt.rows( {page: 'current'} ).iterator( 'row', function ( settings, idx ) {
  137. var row = dt.row( idx );
  138. if ( row.child.isShown() ) {
  139. var info = that.c.details.renderer( dt, idx );
  140. row.child( info, 'child' ).show();
  141. }
  142. } );
  143. } );
  144. $(dt.table().node()).addClass( 'dtr-'+details.type );
  145. }
  146. // First pass - draw the table for the current viewport size
  147. this._resize();
  148. },
  149. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  150. * Private methods
  151. */
  152. /**
  153. * Calculate the visibility for the columns in a table for a given
  154. * breakpoint. The result is pre-determined based on the class logic if
  155. * class names are used to control all columns, but the width of the table
  156. * is also used if there are columns which are to be automatically shown
  157. * and hidden.
  158. *
  159. * @param {string} breakpoint Breakpoint name to use for the calculation
  160. * @return {array} Array of boolean values initiating the visibility of each
  161. * column.
  162. * @private
  163. */
  164. _columnsVisiblity: function ( breakpoint )
  165. {
  166. var dt = this.s.dt;
  167. var columns = this.s.columns;
  168. var i, ien;
  169. // Class logic - determine which columns are in this breakpoint based
  170. // on the classes. If no class control (i.e. `auto`) then `-` is used
  171. // to indicate this to the rest of the function
  172. var display = $.map( columns, function ( col ) {
  173. return col.auto && col.minWidth === null ?
  174. false :
  175. col.auto === true ?
  176. '-' :
  177. $.inArray( breakpoint, col.includeIn ) !== -1;
  178. } );
  179. // Auto column control - first pass: how much width is taken by the
  180. // ones that must be included from the non-auto columns
  181. var requiredWidth = 0;
  182. for ( i=0, ien=display.length ; i<ien ; i++ ) {
  183. if ( display[i] === true ) {
  184. requiredWidth += columns[i].minWidth;
  185. }
  186. }
  187. // Second pass, use up any remaining width for other columns. For
  188. // scrolling tables we need to subtract the width of the scrollbar. It
  189. // may not be requires which makes this sub-optimal, but it would
  190. // require another full redraw to make complete use of those extra few
  191. // pixels
  192. var scrolling = dt.settings()[0].oScroll;
  193. var bar = scrolling.sY || scrolling.sX ? scrolling.iBarWidth : 0;
  194. var widthAvailable = dt.table().container().offsetWidth - bar;
  195. var usedWidth = widthAvailable - requiredWidth;
  196. // Control column needs to always be included. This makes it sub-
  197. // optimal in terms of using the available with, but to stop layout
  198. // thrashing or overflow. Also we need to account for the control column
  199. // width first so we know how much width is available for the other
  200. // columns, since the control column might not be the first one shown
  201. for ( i=0, ien=display.length ; i<ien ; i++ ) {
  202. if ( columns[i].control ) {
  203. usedWidth -= columns[i].minWidth;
  204. }
  205. }
  206. // Allow columns to be shown (counting from the left) until we run out
  207. // of room
  208. var empty = false;
  209. for ( i=0, ien=display.length ; i<ien ; i++ ) {
  210. if ( display[i] === '-' && ! columns[i].control ) {
  211. // Once we've found a column that won't fit we don't let any
  212. // others display either, or columns might disappear in the
  213. // middle of the table
  214. if ( empty || usedWidth - columns[i].minWidth < 0 ) {
  215. empty = true;
  216. display[i] = false;
  217. }
  218. else {
  219. display[i] = true;
  220. }
  221. usedWidth -= columns[i].minWidth;
  222. }
  223. }
  224. // Determine if the 'control' column should be shown (if there is one).
  225. // This is the case when there is a hidden column (that is not the
  226. // control column). The two loops look inefficient here, but they are
  227. // trivial and will fly through. We need to know the outcome from the
  228. // first , before the action in the second can be taken
  229. var showControl = false;
  230. for ( i=0, ien=columns.length ; i<ien ; i++ ) {
  231. if ( ! columns[i].control && ! columns[i].never && ! display[i] ) {
  232. showControl = true;
  233. break;
  234. }
  235. }
  236. for ( i=0, ien=columns.length ; i<ien ; i++ ) {
  237. if ( columns[i].control ) {
  238. display[i] = showControl;
  239. }
  240. }
  241. // Finally we need to make sure that there is at least one column that
  242. // is visible
  243. if ( $.inArray( true, display ) === -1 ) {
  244. display[0] = true;
  245. }
  246. return display;
  247. },
  248. /**
  249. * Create the internal `columns` array with information about the columns
  250. * for the table. This includes determining which breakpoints the column
  251. * will appear in, based upon class names in the column, which makes up the
  252. * vast majority of this method.
  253. *
  254. * @private
  255. */
  256. _classLogic: function ()
  257. {
  258. var that = this;
  259. var calc = {};
  260. var breakpoints = this.c.breakpoints;
  261. var columns = this.s.dt.columns().eq(0).map( function (i) {
  262. var className = this.column(i).header().className;
  263. return {
  264. className: className,
  265. includeIn: [],
  266. auto: false,
  267. control: false,
  268. never: className.match(/\bnever\b/) ? true : false
  269. };
  270. } );
  271. // Simply add a breakpoint to `includeIn` array, ensuring that there are
  272. // no duplicates
  273. var add = function ( colIdx, name ) {
  274. var includeIn = columns[ colIdx ].includeIn;
  275. if ( $.inArray( name, includeIn ) === -1 ) {
  276. includeIn.push( name );
  277. }
  278. };
  279. var column = function ( colIdx, name, operator, matched ) {
  280. var size, i, ien;
  281. if ( ! operator ) {
  282. columns[ colIdx ].includeIn.push( name );
  283. }
  284. else if ( operator === 'max-' ) {
  285. // Add this breakpoint and all smaller
  286. size = that._find( name ).width;
  287. for ( i=0, ien=breakpoints.length ; i<ien ; i++ ) {
  288. if ( breakpoints[i].width <= size ) {
  289. add( colIdx, breakpoints[i].name );
  290. }
  291. }
  292. }
  293. else if ( operator === 'min-' ) {
  294. // Add this breakpoint and all larger
  295. size = that._find( name ).width;
  296. for ( i=0, ien=breakpoints.length ; i<ien ; i++ ) {
  297. if ( breakpoints[i].width >= size ) {
  298. add( colIdx, breakpoints[i].name );
  299. }
  300. }
  301. }
  302. else if ( operator === 'not-' ) {
  303. // Add all but this breakpoint (xxx need extra information)
  304. for ( i=0, ien=breakpoints.length ; i<ien ; i++ ) {
  305. if ( breakpoints[i].name.indexOf( matched ) === -1 ) {
  306. add( colIdx, breakpoints[i].name );
  307. }
  308. }
  309. }
  310. };
  311. // Loop over each column and determine if it has a responsive control
  312. // class
  313. columns.each( function ( col, i ) {
  314. var classNames = col.className.split(' ');
  315. var hasClass = false;
  316. // Split the class name up so multiple rules can be applied if needed
  317. for ( var k=0, ken=classNames.length ; k<ken ; k++ ) {
  318. var className = $.trim( classNames[k] );
  319. if ( className === 'all' ) {
  320. // Include in all
  321. hasClass = true;
  322. col.includeIn = $.map( breakpoints, function (a) {
  323. return a.name;
  324. } );
  325. return;
  326. }
  327. else if ( className === 'none' || className === 'never' ) {
  328. // Include in none (default) and no auto
  329. hasClass = true;
  330. return;
  331. }
  332. else if ( className === 'control' ) {
  333. // Special column that is only visible, when one of the other
  334. // columns is hidden. This is used for the details control
  335. hasClass = true;
  336. col.control = true;
  337. return;
  338. }
  339. $.each( breakpoints, function ( j, breakpoint ) {
  340. // Does this column have a class that matches this breakpoint?
  341. var brokenPoint = breakpoint.name.split('-');
  342. var re = new RegExp( '(min\\-|max\\-|not\\-)?('+brokenPoint[0]+')(\\-[_a-zA-Z0-9])?' );
  343. var match = className.match( re );
  344. if ( match ) {
  345. hasClass = true;
  346. if ( match[2] === brokenPoint[0] && match[3] === '-'+brokenPoint[1] ) {
  347. // Class name matches breakpoint name fully
  348. column( i, breakpoint.name, match[1], match[2]+match[3] );
  349. }
  350. else if ( match[2] === brokenPoint[0] && ! match[3] ) {
  351. // Class name matched primary breakpoint name with no qualifier
  352. column( i, breakpoint.name, match[1], match[2] );
  353. }
  354. }
  355. } );
  356. }
  357. // If there was no control class, then automatic sizing is used
  358. if ( ! hasClass ) {
  359. col.auto = true;
  360. }
  361. } );
  362. this.s.columns = columns;
  363. },
  364. /**
  365. * Initialisation for the details handler
  366. *
  367. * @private
  368. */
  369. _detailsInit: function ()
  370. {
  371. var that = this;
  372. var dt = this.s.dt;
  373. var details = this.c.details;
  374. // The inline type always uses the first child as the target
  375. if ( details.type === 'inline' ) {
  376. details.target = 'td:first-child';
  377. }
  378. // type.target can be a string jQuery selector or a column index
  379. var target = details.target;
  380. var selector = typeof target === 'string' ? target : 'td';
  381. // Click handler to show / hide the details rows when they are available
  382. $( dt.table().body() ).on( 'click', selector, function (e) {
  383. // If the table is not collapsed (i.e. there is no hidden columns)
  384. // then take no action
  385. if ( ! $(dt.table().node()).hasClass('collapsed' ) ) {
  386. return;
  387. }
  388. // Check that the row is actually a DataTable's controlled node
  389. if ( ! dt.row( $(this).closest('tr') ).length ) {
  390. return;
  391. }
  392. // For column index, we determine if we should act or not in the
  393. // handler - otherwise it is already okay
  394. if ( typeof target === 'number' ) {
  395. var targetIdx = target < 0 ?
  396. dt.columns().eq(0).length + target :
  397. target;
  398. if ( dt.cell( this ).index().column !== targetIdx ) {
  399. return;
  400. }
  401. }
  402. // $().closest() includes itself in its check
  403. var row = dt.row( $(this).closest('tr') );
  404. if ( row.child.isShown() ) {
  405. row.child( false );
  406. $( row.node() ).removeClass( 'parent' );
  407. }
  408. else {
  409. var info = that.c.details.renderer( dt, row[0] );
  410. row.child( info, 'child' ).show();
  411. $( row.node() ).addClass( 'parent' );
  412. }
  413. } );
  414. },
  415. /**
  416. * Update the child rows in the table whenever the column visibility changes
  417. *
  418. * @private
  419. */
  420. _detailsVis: function ()
  421. {
  422. var that = this;
  423. var dt = this.s.dt;
  424. // Find how many columns are hidden
  425. var hiddenColumns = dt.columns().indexes().filter( function ( idx ) {
  426. var col = dt.column( idx );
  427. if ( col.visible() ) {
  428. return null;
  429. }
  430. // Only counts as hidden if it doesn't have the `never` class
  431. return $( col.header() ).hasClass( 'never' ) ? null : idx;
  432. } );
  433. var haveHidden = true;
  434. if ( hiddenColumns.length === 0 || ( hiddenColumns.length === 1 && this.s.columns[ hiddenColumns[0] ].control ) ) {
  435. haveHidden = false;
  436. }
  437. if ( haveHidden ) {
  438. // Show all existing child rows
  439. dt.rows( { page: 'current' } ).eq(0).each( function (idx) {
  440. var row = dt.row( idx );
  441. if ( row.child() ) {
  442. var info = that.c.details.renderer( dt, row[0] );
  443. // The renderer can return false to have no child row
  444. if ( info === false ) {
  445. row.child.hide();
  446. }
  447. else {
  448. row.child( info, 'child' ).show();
  449. }
  450. }
  451. } );
  452. }
  453. else {
  454. // Hide all existing child rows
  455. dt.rows( { page: 'current' } ).eq(0).each( function (idx) {
  456. dt.row( idx ).child.hide();
  457. } );
  458. }
  459. },
  460. /**
  461. * Find a breakpoint object from a name
  462. * @param {string} name Breakpoint name to find
  463. * @return {object} Breakpoint description object
  464. */
  465. _find: function ( name )
  466. {
  467. var breakpoints = this.c.breakpoints;
  468. for ( var i=0, ien=breakpoints.length ; i<ien ; i++ ) {
  469. if ( breakpoints[i].name === name ) {
  470. return breakpoints[i];
  471. }
  472. }
  473. },
  474. /**
  475. * Alter the table display for a resized viewport. This involves first
  476. * determining what breakpoint the window currently is in, getting the
  477. * column visibilities to apply and then setting them.
  478. *
  479. * @private
  480. */
  481. _resize: function ()
  482. {
  483. var dt = this.s.dt;
  484. var width = $(window).width();
  485. var breakpoints = this.c.breakpoints;
  486. var breakpoint = breakpoints[0].name;
  487. var columns = this.s.columns;
  488. var i, ien;
  489. // Determine what breakpoint we are currently at
  490. for ( i=breakpoints.length-1 ; i>=0 ; i-- ) {
  491. if ( width <= breakpoints[i].width ) {
  492. breakpoint = breakpoints[i].name;
  493. break;
  494. }
  495. }
  496. // Show the columns for that break point
  497. var columnsVis = this._columnsVisiblity( breakpoint );
  498. // Set the class before the column visibility is changed so event
  499. // listeners know what the state is. Need to determine if there are
  500. // any columns that are not visible but can be shown
  501. var collapsedClass = false;
  502. for ( i=0, ien=columns.length ; i<ien ; i++ ) {
  503. if ( columnsVis[i] === false && ! columns[i].never ) {
  504. collapsedClass = true;
  505. break;
  506. }
  507. }
  508. $( dt.table().node() ).toggleClass('collapsed', collapsedClass );
  509. dt.columns().eq(0).each( function ( colIdx, i ) {
  510. dt.column( colIdx ).visible( columnsVis[i] );
  511. } );
  512. },
  513. /**
  514. * Determine the width of each column in the table so the auto column hiding
  515. * has that information to work with. This method is never going to be 100%
  516. * perfect since column widths can change slightly per page, but without
  517. * seriously compromising performance this is quite effective.
  518. *
  519. * @private
  520. */
  521. _resizeAuto: function ()
  522. {
  523. var dt = this.s.dt;
  524. var columns = this.s.columns;
  525. // Are we allowed to do auto sizing?
  526. if ( ! this.c.auto ) {
  527. return;
  528. }
  529. // Are there any columns that actually need auto-sizing, or do they all
  530. // have classes defined
  531. if ( $.inArray( true, $.map( columns, function (c) { return c.auto; } ) ) === -1 ) {
  532. return;
  533. }
  534. // Clone the table with the current data in it
  535. var tableWidth = dt.table().node().offsetWidth;
  536. var columnWidths = dt.columns;
  537. var clonedTable = dt.table().node().cloneNode( false );
  538. var clonedHeader = $( dt.table().header().cloneNode( false ) ).appendTo( clonedTable );
  539. var clonedBody = $( dt.table().body().cloneNode( false ) ).appendTo( clonedTable );
  540. $( dt.table().footer() ).clone( false ).appendTo( clonedTable );
  541. // This is a bit slow, but we need to get a clone of each row that
  542. // includes all columns. As such, try to do this as little as possible.
  543. dt.rows( { page: 'current' } ).indexes().flatten().each( function ( idx ) {
  544. var clone = dt.row( idx ).node().cloneNode( true );
  545. if ( dt.columns( ':hidden' ).flatten().length ) {
  546. $(clone).append( dt.cells( idx, ':hidden' ).nodes().to$().clone() );
  547. }
  548. $(clone).appendTo( clonedBody );
  549. } );
  550. var cells = dt.columns().header().to$().clone( false );
  551. $('<tr/>')
  552. .append( cells )
  553. .appendTo( clonedHeader );
  554. // In the inline case extra padding is applied to the first column to
  555. // give space for the show / hide icon. We need to use this in the
  556. // calculation
  557. if ( this.c.details.type === 'inline' ) {
  558. $(clonedTable).addClass( 'dtr-inline collapsed' );
  559. }
  560. var inserted = $('<div/>')
  561. .css( {
  562. width: 1,
  563. height: 1,
  564. overflow: 'hidden'
  565. } )
  566. .append( clonedTable );
  567. // Remove columns which are not to be included
  568. inserted.find('th.never, td.never').remove();
  569. inserted.insertBefore( dt.table().node() );
  570. // The cloned header now contains the smallest that each column can be
  571. dt.columns().eq(0).each( function ( idx ) {
  572. columns[idx].minWidth = cells[ idx ].offsetWidth || 0;
  573. } );
  574. inserted.remove();
  575. }
  576. };
  577. /**
  578. * List of default breakpoints. Each item in the array is an object with two
  579. * properties:
  580. *
  581. * * `name` - the breakpoint name.
  582. * * `width` - the breakpoint width
  583. *
  584. * @name Responsive.breakpoints
  585. * @static
  586. */
  587. Responsive.breakpoints = [
  588. { name: 'desktop', width: Infinity },
  589. { name: 'tablet-l', width: 1024 },
  590. { name: 'tablet-p', width: 768 },
  591. { name: 'mobile-l', width: 480 },
  592. { name: 'mobile-p', width: 320 }
  593. ];
  594. /**
  595. * Responsive default settings for initialisation
  596. *
  597. * @namespace
  598. * @name Responsive.defaults
  599. * @static
  600. */
  601. Responsive.defaults = {
  602. /**
  603. * List of breakpoints for the instance. Note that this means that each
  604. * instance can have its own breakpoints. Additionally, the breakpoints
  605. * cannot be changed once an instance has been creased.
  606. *
  607. * @type {Array}
  608. * @default Takes the value of `Responsive.breakpoints`
  609. */
  610. breakpoints: Responsive.breakpoints,
  611. /**
  612. * Enable / disable auto hiding calculations. It can help to increase
  613. * performance slightly if you disable this option, but all columns would
  614. * need to have breakpoint classes assigned to them
  615. *
  616. * @type {Boolean}
  617. * @default `true`
  618. */
  619. auto: true,
  620. /**
  621. * Details control. If given as a string value, the `type` property of the
  622. * default object is set to that value, and the defaults used for the rest
  623. * of the object - this is for ease of implementation.
  624. *
  625. * The object consists of the following properties:
  626. *
  627. * * `renderer` - function that is called for display of the child row data.
  628. * The default function will show the data from the hidden columns
  629. * * `target` - Used as the selector for what objects to attach the child
  630. * open / close to
  631. * * `type` - `false` to disable the details display, `inline` or `column`
  632. * for the two control types
  633. *
  634. * @type {Object|string}
  635. */
  636. details: {
  637. renderer: function ( api, rowIdx ) {
  638. var data = api.cells( rowIdx, ':hidden' ).eq(0).map( function ( cell ) {
  639. var header = $( api.column( cell.column ).header() );
  640. var idx = api.cell( cell ).index();
  641. if ( header.hasClass( 'control' ) || header.hasClass( 'never' ) ) {
  642. return '';
  643. }
  644. // Use a non-public DT API method to render the data for display
  645. // This needs to be updated when DT adds a suitable method for
  646. // this type of data retrieval
  647. var dtPrivate = api.settings()[0];
  648. var cellData = dtPrivate.oApi._fnGetCellData(
  649. dtPrivate, idx.row, idx.column, 'display'
  650. );
  651. var title = header.find('span').text()?header.find('span').text():header.text();
  652. if ( title ) {
  653. title = title + ':';
  654. }
  655. return '<li data-dtr-index="'+idx.column+'">'+
  656. '<span class="dtr-title">'+
  657. title+
  658. '</span> '+
  659. '<span class="dtr-data">'+
  660. cellData+
  661. '</span>'+
  662. '</li>';
  663. } ).toArray().join('');
  664. return data ?
  665. $('<ul data-dtr-index="'+rowIdx+'"/>').append( data ) :
  666. false;
  667. },
  668. target: 0,
  669. type: 'inline'
  670. }
  671. };
  672. /*
  673. * API
  674. */
  675. var Api = $.fn.dataTable.Api;
  676. // Doesn't do anything - work around for a bug in DT... Not documented
  677. Api.register( 'responsive()', function () {
  678. return this;
  679. } );
  680. Api.register( 'responsive.index()', function ( li ) {
  681. li = $(li);
  682. return {
  683. column: li.data('dtr-index'),
  684. row: li.parent().data('dtr-index')
  685. };
  686. } );
  687. Api.register( 'responsive.rebuild()', function () {
  688. return this.iterator( 'table', function ( ctx ) {
  689. if ( ctx._responsive ) {
  690. ctx._responsive._classLogic();
  691. }
  692. } );
  693. } );
  694. Api.register( 'responsive.recalc()', function () {
  695. return this.iterator( 'table', function ( ctx ) {
  696. if ( ctx._responsive ) {
  697. ctx._responsive._resizeAuto();
  698. ctx._responsive._resize();
  699. }
  700. } );
  701. } );
  702. /**
  703. * Version information
  704. *
  705. * @name Responsive.version
  706. * @static
  707. */
  708. Responsive.version = '1.0.6';
  709. $.fn.dataTable.Responsive = Responsive;
  710. $.fn.DataTable.Responsive = Responsive;
  711. // Attach a listener to the document which listens for DataTables initialisation
  712. // events so we can automatically initialise
  713. $(document).on( 'init.dt.dtr', function (e, settings, json) {
  714. if ( e.namespace !== 'dt' ) {
  715. return;
  716. }
  717. if ( $(settings.nTable).hasClass( 'responsive' ) ||
  718. $(settings.nTable).hasClass( 'dt-responsive' ) ||
  719. settings.oInit.responsive ||
  720. DataTable.defaults.responsive
  721. ) {
  722. var init = settings.oInit.responsive;
  723. if ( init !== false ) {
  724. new Responsive( settings, $.isPlainObject( init ) ? init : {} );
  725. }
  726. }
  727. } );
  728. return Responsive;
  729. }; // /factory
  730. // Define as an AMD module if possible
  731. if ( typeof define === 'function' && define.amd ) {
  732. define( ['jquery', 'datatables'], factory );
  733. }
  734. else if ( typeof exports === 'object' ) {
  735. // Node/CommonJS
  736. factory( require('jquery'), require('datatables') );
  737. }
  738. else if ( jQuery && !jQuery.fn.dataTable.Responsive ) {
  739. // Otherwise simply initialise as normal, stopping multiple evaluation
  740. factory( jQuery, jQuery.fn.dataTable );
  741. }
  742. })(window, document);