dataTables.responsive.js 21 KB

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