dataTables.responsive.js 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801
  1. /*! Responsive 1.0.2
  2. * 2014 SpryMedia Ltd - datatables.net/license
  3. */
  4. /**
  5. * @summary Responsive
  6. * @description Responsive tables plug-in for DataTables
  7. * @version 1.0.2
  8. * @file dataTables.responsive.js
  9. * @author SpryMedia Ltd (www.sprymedia.co.uk)
  10. * @contact www.sprymedia.co.uk/contact
  11. * @copyright Copyright 2014 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' );
  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. // First pass - draw the table for the current viewport size
  126. this._resize();
  127. // Details handler
  128. var details = this.c.details;
  129. if ( details.type ) {
  130. that._detailsInit();
  131. this._detailsVis();
  132. dt.on( 'column-visibility.dtr', function () {
  133. that._detailsVis();
  134. } );
  135. $(dt.table().node()).addClass( 'dtr-'+details.type );
  136. }
  137. },
  138. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  139. * Private methods
  140. */
  141. /**
  142. * Calculate the visibility for the columns in a table for a given
  143. * breakpoint. The result is pre-determined based on the class logic if
  144. * class names are used to control all columns, but the width of the table
  145. * is also used if there are columns which are to be automatically shown
  146. * and hidden.
  147. *
  148. * @param {string} breakpoint Breakpoint name to use for the calculation
  149. * @return {array} Array of boolean values initiating the visibility of each
  150. * column.
  151. * @private
  152. */
  153. _columnsVisiblity: function ( breakpoint )
  154. {
  155. var dt = this.s.dt;
  156. var columns = this.s.columns;
  157. var i, ien;
  158. // Class logic - determine which columns are in this breakpoint based
  159. // on the classes. If no class control (i.e. `auto`) then `-` is used
  160. // to indicate this to the rest of the function
  161. var display = $.map( columns, function ( col ) {
  162. return col.auto && col.minWidth === null ?
  163. false :
  164. col.auto === true ?
  165. '-' :
  166. $.inArray( breakpoint, col.includeIn ) !== -1;
  167. } );
  168. // Auto column control - first pass: how much width is taken by the
  169. // ones that must be included from the non-auto columns
  170. var requiredWidth = 0;
  171. for ( i=0, ien=display.length ; i<ien ; i++ ) {
  172. if ( display[i] === true ) {
  173. requiredWidth += columns[i].minWidth;
  174. }
  175. }
  176. // Second pass, use up any remaining width for other columns
  177. var widthAvailable = dt.table().container().offsetWidth;
  178. var usedWidth = widthAvailable - requiredWidth;
  179. for ( i=0, ien=display.length ; i<ien ; i++ ) {
  180. // Control column needs to always be included. This makes it sub-
  181. // optimal in terms of using the available with, but to stop layout
  182. // thrashing or overflow
  183. if ( columns[i].control ) {
  184. usedWidth -= columns[i].minWidth;
  185. }
  186. else if ( display[i] === '-' ) {
  187. // Otherwise, remove the width
  188. display[i] = usedWidth - columns[i].minWidth < 0 ?
  189. false :
  190. true;
  191. // Continue counting down the width, so a smaller column to the
  192. // left won't be shown
  193. usedWidth -= columns[i].minWidth;
  194. }
  195. }
  196. // Determine if the 'control' column should be shown (if there is one).
  197. // This is the case when there is a hidden column (that is not the
  198. // control column). The two loops look inefficient here, but they are
  199. // trivial and will fly through. We need to know the outcome from the
  200. // first , before the action in the second can be taken
  201. var showControl = false;
  202. for ( i=0, ien=columns.length ; i<ien ; i++ ) {
  203. if ( ! columns[i].control && ! columns[i].never && ! display[i] ) {
  204. showControl = true;
  205. break;
  206. }
  207. }
  208. for ( i=0, ien=columns.length ; i<ien ; i++ ) {
  209. if ( columns[i].control ) {
  210. display[i] = showControl;
  211. }
  212. }
  213. // Finally we need to make sure that there is at least one column that
  214. // is visible
  215. if ( $.inArray( true, display ) === -1 ) {
  216. display[0] = true;
  217. }
  218. return display;
  219. },
  220. /**
  221. * Create the internal `columns` array with information about the columns
  222. * for the table. This includes determining which breakpoints the column
  223. * will appear in, based upon class names in the column, which makes up the
  224. * vast majority of this method.
  225. *
  226. * @private
  227. */
  228. _classLogic: function ()
  229. {
  230. var that = this;
  231. var calc = {};
  232. var breakpoints = this.c.breakpoints;
  233. var columns = this.s.dt.columns().eq(0).map( function (i) {
  234. var className = this.column(i).header().className;
  235. return {
  236. className: className,
  237. includeIn: [],
  238. auto: false,
  239. control: false,
  240. never: className.match(/\bnever\b/) ? true : false
  241. };
  242. } );
  243. // Simply add a breakpoint to `includeIn` array, ensuring that there are
  244. // no duplicates
  245. var add = function ( colIdx, name ) {
  246. var includeIn = columns[ colIdx ].includeIn;
  247. if ( $.inArray( name, includeIn ) === -1 ) {
  248. includeIn.push( name );
  249. }
  250. };
  251. var column = function ( colIdx, name, operator, matched ) {
  252. var size, i, ien;
  253. if ( ! operator ) {
  254. columns[ colIdx ].includeIn.push( name );
  255. }
  256. else if ( operator === 'max-' ) {
  257. // Add this breakpoint and all smaller
  258. size = that._find( name ).width;
  259. for ( i=0, ien=breakpoints.length ; i<ien ; i++ ) {
  260. if ( breakpoints[i].width <= size ) {
  261. add( colIdx, breakpoints[i].name );
  262. }
  263. }
  264. }
  265. else if ( operator === 'min-' ) {
  266. // Add this breakpoint and all larger
  267. size = that._find( name ).width;
  268. for ( i=0, ien=breakpoints.length ; i<ien ; i++ ) {
  269. if ( breakpoints[i].width >= size ) {
  270. add( colIdx, breakpoints[i].name );
  271. }
  272. }
  273. }
  274. else if ( operator === 'not-' ) {
  275. // Add all but this breakpoint (xxx need extra information)
  276. for ( i=0, ien=breakpoints.length ; i<ien ; i++ ) {
  277. if ( breakpoints[i].name.indexOf( matched ) === -1 ) {
  278. add( colIdx, breakpoints[i].name );
  279. }
  280. }
  281. }
  282. };
  283. // Loop over each column and determine if it has a responsive control
  284. // class
  285. columns.each( function ( col, i ) {
  286. var classNames = col.className.split(' ');
  287. var hasClass = false;
  288. // Split the class name up so multiple rules can be applied if needed
  289. for ( var k=0, ken=classNames.length ; k<ken ; k++ ) {
  290. var className = $.trim( classNames[k] );
  291. if ( className === 'all' ) {
  292. // Include in all
  293. hasClass = true;
  294. col.includeIn = $.map( breakpoints, function (a) {
  295. return a.name;
  296. } );
  297. return;
  298. }
  299. else if ( className === 'none' || className === 'never' ) {
  300. // Include in none (default) and no auto
  301. hasClass = true;
  302. return;
  303. }
  304. else if ( className === 'control' ) {
  305. // Special column that is only visible, when one of the other
  306. // columns is hidden. This is used for the details control
  307. hasClass = true;
  308. col.control = true;
  309. return;
  310. }
  311. $.each( breakpoints, function ( j, breakpoint ) {
  312. // Does this column have a class that matches this breakpoint?
  313. var brokenPoint = breakpoint.name.split('-');
  314. var re = new RegExp( '(min\\-|max\\-|not\\-)?('+brokenPoint[0]+')(\\-[_a-zA-Z0-9])?' );
  315. var match = className.match( re );
  316. if ( match ) {
  317. hasClass = true;
  318. if ( match[2] === brokenPoint[0] && match[3] === '-'+brokenPoint[1] ) {
  319. // Class name matches breakpoint name fully
  320. column( i, breakpoint.name, match[1], match[2]+match[3] );
  321. }
  322. else if ( match[2] === brokenPoint[0] && ! match[3] ) {
  323. // Class name matched primary breakpoint name with no qualifier
  324. column( i, breakpoint.name, match[1], match[2] );
  325. }
  326. }
  327. } );
  328. }
  329. // If there was no control class, then automatic sizing is used
  330. if ( ! hasClass ) {
  331. col.auto = true;
  332. }
  333. } );
  334. this.s.columns = columns;
  335. },
  336. /**
  337. * Initialisation for the details handler
  338. *
  339. * @private
  340. */
  341. _detailsInit: function ()
  342. {
  343. var that = this;
  344. var dt = this.s.dt;
  345. var details = this.c.details;
  346. // The inline type always uses the first child as the target
  347. if ( details.type === 'inline' ) {
  348. details.target = 'td:first-child';
  349. }
  350. // type.target can be a string jQuery selector or a column index
  351. var target = details.target;
  352. var selector = typeof target === 'string' ? target : 'td';
  353. // Click handler to show / hide the details rows when they are available
  354. $( dt.table().body() ).on( 'click', selector, function (e) {
  355. // If the table is not collapsed (i.e. there is no hidden columns)
  356. // then take no action
  357. if ( ! $(dt.table().node()).hasClass('collapsed' ) ) {
  358. return;
  359. }
  360. // Check that the row is actually a DataTable's controlled node
  361. if ( ! dt.row( $(this).closest('tr') ).length ) {
  362. return;
  363. }
  364. // For column index, we determine if we should act or not in the
  365. // handler - otherwise it is already okay
  366. if ( typeof target === 'number' ) {
  367. var targetIdx = target < 0 ?
  368. dt.columns().eq(0).length + target :
  369. target;
  370. if ( dt.cell( this ).index().column !== targetIdx ) {
  371. return;
  372. }
  373. }
  374. // $().closest() includes itself in its check
  375. var row = dt.row( $(this).closest('tr') );
  376. if ( row.child.isShown() ) {
  377. row.child( false );
  378. $( row.node() ).removeClass( 'parent' );
  379. }
  380. else {
  381. var info = that.c.details.renderer( dt, row[0] );
  382. row.child( info, 'child' ).show();
  383. $( row.node() ).addClass( 'parent' );
  384. }
  385. } );
  386. },
  387. /**
  388. * Update the child rows in the table whenever the column visibility changes
  389. *
  390. * @private
  391. */
  392. _detailsVis: function ()
  393. {
  394. var that = this;
  395. var dt = this.s.dt;
  396. // Find how many columns are hidden
  397. var hiddenColumns = dt.columns().indexes().filter( function ( idx ) {
  398. var col = dt.column( idx );
  399. if ( col.visible() ) {
  400. return null;
  401. }
  402. // Only counts as hidden if it doesn't have the `never` class
  403. return $( col.header() ).hasClass( 'never' ) ? null : idx;
  404. } );
  405. var haveHidden = true;
  406. if ( hiddenColumns.length === 0 || ( hiddenColumns.length === 1 && this.s.columns[ hiddenColumns[0] ].control ) ) {
  407. haveHidden = false;
  408. }
  409. if ( haveHidden ) {
  410. // Got hidden columns
  411. $( dt.table().node() ).addClass('collapsed');
  412. // Show all existing child rows
  413. dt.rows().eq(0).each( function (idx) {
  414. var row = dt.row( idx );
  415. if ( row.child() ) {
  416. var info = that.c.details.renderer( dt, row[0] );
  417. // The renderer can return false to have no child row
  418. if ( info === false ) {
  419. row.child.hide();
  420. }
  421. else {
  422. row.child( info, 'child' ).show();
  423. }
  424. }
  425. } );
  426. }
  427. else {
  428. // No hidden columns
  429. $( dt.table().node() ).removeClass('collapsed');
  430. // Hide all existing child rows
  431. dt.rows().eq(0).each( function (idx) {
  432. dt.row( idx ).child.hide();
  433. } );
  434. }
  435. },
  436. /**
  437. * Find a breakpoint object from a name
  438. * @param {string} name Breakpoint name to find
  439. * @return {object} Breakpoint description object
  440. */
  441. _find: function ( name )
  442. {
  443. var breakpoints = this.c.breakpoints;
  444. for ( var i=0, ien=breakpoints.length ; i<ien ; i++ ) {
  445. if ( breakpoints[i].name === name ) {
  446. return breakpoints[i];
  447. }
  448. }
  449. },
  450. /**
  451. * Alter the table display for a resized viewport. This involves first
  452. * determining what breakpoint the window currently is in, getting the
  453. * column visibilities to apply and then setting them.
  454. *
  455. * @private
  456. */
  457. _resize: function ()
  458. {
  459. var dt = this.s.dt;
  460. var width = $(window).width();
  461. var breakpoints = this.c.breakpoints;
  462. var breakpoint = breakpoints[0].name;
  463. // Determine what breakpoint we are currently at
  464. for ( var i=breakpoints.length-1 ; i>=0 ; i-- ) {
  465. if ( width <= breakpoints[i].width ) {
  466. breakpoint = breakpoints[i].name;
  467. break;
  468. }
  469. }
  470. // Show the columns for that break point
  471. var columns = this._columnsVisiblity( breakpoint );
  472. dt.columns().eq(0).each( function ( colIdx, i ) {
  473. dt.column( colIdx ).visible( columns[i] );
  474. } );
  475. },
  476. /**
  477. * Determine the width of each column in the table so the auto column hiding
  478. * has that information to work with. This method is never going to be 100%
  479. * perfect since column widths can change slightly per page, but without
  480. * seriously compromising performance this is quite effective.
  481. *
  482. * @private
  483. */
  484. _resizeAuto: function ()
  485. {
  486. var dt = this.s.dt;
  487. var columns = this.s.columns;
  488. // Are we allowed to do auto sizing?
  489. if ( ! this.c.auto ) {
  490. return;
  491. }
  492. // Are there any columns that actually need auto-sizing, or do they all
  493. // have classes defined
  494. if ( $.inArray( true, $.map( columns, function (c) { return c.auto; } ) ) === -1 ) {
  495. return;
  496. }
  497. // Clone the table with the current data in it
  498. var tableWidth = dt.table().node().offsetWidth;
  499. var columnWidths = dt.columns;
  500. var clonedTable = dt.table().node().cloneNode( false );
  501. var clonedHeader = $( dt.table().header().cloneNode( false ) ).appendTo( clonedTable );
  502. var clonedBody = $( dt.table().body().cloneNode( false ) ).appendTo( clonedTable );
  503. // This is a bit slow, but we need to get a clone of each row that
  504. // includes all columns. As such, try to do this as little as possible.
  505. dt.rows( { page: 'current' } ).indexes().flatten().each( function ( idx ) {
  506. var clone = dt.row( idx ).node().cloneNode( true );
  507. if ( dt.columns( ':hidden' ).flatten().length ) {
  508. $(clone).append( dt.cells( idx, ':hidden' ).nodes().to$().clone() );
  509. }
  510. $(clone).appendTo( clonedBody );
  511. } );
  512. var cells = dt.columns().header().to$().clone( false ).wrapAll('tr').appendTo( clonedHeader );
  513. var inserted = $('<div/>')
  514. .css( {
  515. width: 1,
  516. height: 1,
  517. overflow: 'hidden'
  518. } )
  519. .append( clonedTable )
  520. .insertBefore( dt.table().node() );
  521. // The cloned header now contains the smallest that each column can be
  522. dt.columns().eq(0).each( function ( idx ) {
  523. columns[idx].minWidth = cells[ idx ].offsetWidth || 0;
  524. } );
  525. inserted.remove();
  526. }
  527. };
  528. /**
  529. * List of default breakpoints. Each item in the array is an object with two
  530. * properties:
  531. *
  532. * * `name` - the breakpoint name.
  533. * * `width` - the breakpoint width
  534. *
  535. * @name Responsive.breakpoints
  536. * @static
  537. */
  538. Responsive.breakpoints = [
  539. { name: 'desktop', width: Infinity },
  540. { name: 'tablet-l', width: 1024 },
  541. { name: 'tablet-p', width: 768 },
  542. { name: 'mobile-l', width: 480 },
  543. { name: 'mobile-p', width: 320 }
  544. ];
  545. /**
  546. * Responsive default settings for initialisation
  547. *
  548. * @namespace
  549. * @name Responsive.defaults
  550. * @static
  551. */
  552. Responsive.defaults = {
  553. /**
  554. * List of breakpoints for the instance. Note that this means that each
  555. * instance can have its own breakpoints. Additionally, the breakpoints
  556. * cannot be changed once an instance has been creased.
  557. *
  558. * @type {Array}
  559. * @default Takes the value of `Responsive.breakpoints`
  560. */
  561. breakpoints: Responsive.breakpoints,
  562. /**
  563. * Enable / disable auto hiding calculations. It can help to increase
  564. * performance slightly if you disable this option, but all columns would
  565. * need to have breakpoint classes assigned to them
  566. *
  567. * @type {Boolean}
  568. * @default `true`
  569. */
  570. auto: true,
  571. /**
  572. * Details control. If given as a string value, the `type` property of the
  573. * default object is set to that value, and the defaults used for the rest
  574. * of the object - this is for ease of implementation.
  575. *
  576. * The object consists of the following properties:
  577. *
  578. * * `renderer` - function that is called for display of the child row data.
  579. * The default function will show the data from the hidden columns
  580. * * `target` - Used as the selector for what objects to attach the child
  581. * open / close to
  582. * * `type` - `false` to disable the details display, `inline` or `column`
  583. * for the two control types
  584. *
  585. * @type {Object|string}
  586. */
  587. details: {
  588. renderer: function ( api, rowIdx ) {
  589. var data = api.cells( rowIdx, ':hidden' ).eq(0).map( function ( cell ) {
  590. var header = $( api.column( cell.column ).header() );
  591. var idx = api.cell( cell ).index();
  592. if ( header.hasClass( 'control' ) || header.hasClass( 'never' ) ) {
  593. return '';
  594. }
  595. // Use a non-public DT API method to render the data for display
  596. // This needs to be updated when DT adds a suitable method for
  597. // this type of data retrieval
  598. var dtPrivate = api.settings()[0];
  599. var cellData = dtPrivate.oApi._fnGetCellData(
  600. dtPrivate, idx.row, idx.column, 'display'
  601. );
  602. return '<li data-dtr-index="'+idx.column+'">'+
  603. '<span class="dtr-title">'+
  604. header.text()+':'+
  605. '</span> '+
  606. '<span class="dtr-data">'+
  607. cellData+
  608. '</span>'+
  609. '</li>';
  610. } ).toArray().join('');
  611. return data ?
  612. $('<ul data-dtr-index="'+rowIdx+'"/>').append( data ) :
  613. false;
  614. },
  615. target: 0,
  616. type: 'inline'
  617. }
  618. };
  619. /*
  620. * API
  621. */
  622. var Api = $.fn.dataTable.Api;
  623. // Doesn't do anything - work around for a bug in DT... Not documented
  624. Api.register( 'responsive()', function () {
  625. return this;
  626. } );
  627. Api.register( 'responsive.recalc()', function () {
  628. this.iterator( 'table', function ( ctx ) {
  629. if ( ctx._responsive ) {
  630. ctx._responsive._resizeAuto();
  631. ctx._responsive._resize();
  632. }
  633. } );
  634. } );
  635. Api.register( 'responsive.index()', function ( li ) {
  636. li = $(li);
  637. return {
  638. column: li.data('dtr-index'),
  639. row: li.parent().data('dtr-index')
  640. };
  641. } );
  642. /**
  643. * Version information
  644. *
  645. * @name Responsive.version
  646. * @static
  647. */
  648. Responsive.version = '1.0.2';
  649. $.fn.dataTable.Responsive = Responsive;
  650. $.fn.DataTable.Responsive = Responsive;
  651. // Attach a listener to the document which listens for DataTables initialisation
  652. // events so we can automatically initialise
  653. $(document).on( 'init.dt.dtr', function (e, settings, json) {
  654. if ( $(settings.nTable).hasClass( 'responsive' ) ||
  655. $(settings.nTable).hasClass( 'dt-responsive' ) ||
  656. settings.oInit.responsive ||
  657. DataTable.defaults.responsive
  658. ) {
  659. var init = settings.oInit.responsive;
  660. if ( init !== false ) {
  661. new Responsive( settings, $.isPlainObject( init ) ? init : {} );
  662. }
  663. }
  664. } );
  665. return Responsive;
  666. }; // /factory
  667. // Define as an AMD module if possible
  668. if ( typeof define === 'function' && define.amd ) {
  669. define( ['jquery', 'datatables'], factory );
  670. }
  671. else if ( typeof exports === 'object' ) {
  672. // Node/CommonJS
  673. factory( require('jquery'), require('datatables') );
  674. }
  675. else if ( jQuery && !jQuery.fn.dataTable.Responsive ) {
  676. // Otherwise simply initialise as normal, stopping multiple evaluation
  677. factory( jQuery, jQuery.fn.dataTable );
  678. }
  679. })(window, document);