- Think this code was in DataTables 1.0 and has been relatively
untouched! A refactor allows it to be more readable and smaller when
compressed (about 450 bytes saved)
- invalidation is going to play an important part in the new API, with
the ability to invalid the cached data for sorting, filtering, display
etc so we need to be able tos upport this in the core.
- In fairness the sorting didn't actually need invalidation because it
would always get data on every sort, which is bad for performance -
proper invalidation and caching will resolve this. Which is what has
been implemented here.
- I had expected (hoped) to be able to save a bit of space in the
refactor, but only aorund 100 bytes (compressed) saved, which will
probably be lost when the invalidation is fully implemented in the
API. Still, better performance, tidier code, and no extra space...
Fix: Sorting classes now show multi column sorting when a column is
defined to sort over multiple columns (sortData). Previously it would
only show the first column.
- Two new methods for the new API to allow new data (rows) to be added
to the table.
- row.add() - Add a single row to the table. object, array, jQuery
object or TR node can be passed in.
- rows.add() - Add one or more rows to the table from a source array.
An array or jQuery object must be passed in, containing objects,
arrays, or TR nodes (or any combination thereof).
- Should be noted that this is iterated over all tables in the current
API context, so care should be taken when adding a node to multiple
tables, since it will be moved between them. Equally, when adding
data, the original object reference is retained, so changing it in one
table will change it in all!
- These two methods effectively replace fnAddData from the old API.
fnAddData had a few issues with distingusihing a multiple row add and
a single row add, since arrays could be used for both (indeed, it
simply couldn't cope with something like using a single integer as
reference for a data object, which can now be done in 1.10). The two
new methods sidestep this problem by providing one method for multiple
row add, and another for single row add - the developer needs to know
that the plural has meaning here!
Only call once each to check to see sort ascending / sort descending is is active. (And only check for the descending class if we didn't find the ascending class)
Should also lead to smaller minified code.
- Addition of a destroy method for the new API, effectively replacing
fnDestroy from the old API.
- The functionality is identical to fnDestroy, but it has been
refactored to make better use of jQuery and allow for better
compression (should be 1/4 - 1/2 KiB saved)
- $ - perform a jQuery selector on the nodes in the table (matching the
$ method from the old API).
- clear - clear the table completely (replaces fnClearTable).
- settings - get an array of the settings objects for the tables used in
the API instance.
- on - jQuery event listener proxy. Use for table specific events
('draw', 'xhr' etc).
- one - jQuery event listener proxy (single event).
- off - jQuery event unlistener proxy.
- Showing and hiding details about a row in a child row is very useful
and proven to be a popular part of DataTables. This commit provides
that ability in the new API and extends it. It also fully modularises
the child rows aspects, so it could be removed from the core without
effecting any other aspects (it may be moved into a seperate file in
future).
- This will effectively replace fnOpen, fnClose and fnIsOpen
- Added methods:
- row( selector, opts ).child()
- row( selector, opts ).child( str, class )
- row( selector, opts ).child( str, class ).show()
- row( selector, opts ).child( str, class ).hide()
- row( selector, opts ).child.show()
- row( selector, opts ).child.hide()
- row( selector, opts ).child.isShown()
- Note that unlike the old API you need to specify the data first, and
then use the show() method to show the child row. This allows the
details rows to be configured before they are actually shown.
- Additionally multiple child rows can be attached to a parent (pass
`str` (from above) as an array to use this feature. API plug-ins could
use this ability to show fully nested tables.
- Not just a string can be passed in now, but also a TR node which will
actually be used (rather than put into a nested row), any other type
of node (which will be inserted into a wrapper row/cell) or a jQuery
object.
- The rows() method allows operations on multiple rows with a single
call, this new singualr option, `row()` performs operations on a
single row, allowing fine grain control and easy access to certain
aspects. For example. `rows().data()` will return an array of data
objects, even if there is only one row as a result of the selector,
while `row().data()` will return the data object directly.
- Impletemented thus far:
- row()
- row().node()
- row().cells()
- row().data() - get only as of yet
- row().index()
- row().remove()
- Previously it was the domain of the filtering caller to update the
global filtering input element (fnFilter or the keypress handler
specifically), but in keeping with the drive towards modularity, it
should be the control itself that updates when needed.
- This is done by listening for the `filter` event from the table and
updating the display as needed. It is a touch less efficent since the
same value might be written as what is already there, but it reduces
code size and complexity.
- Ability to filter the table through the new API.
- This effectively replaces the fnFilter method of the old API.
- Note that one capability which has been removed from the old API is the
ability to not show the new filter on the filtering input elements. I
can't see any use for that feature to be honest, so it has been
dropped. The filtering inputs always show the global filter state now.
- Additionally, note that we've been forced to call this `search` here
rather than `filter` since there is a `filter` method for the API
collection instance. This might be revisted before release.
- The fnVisibleToColumnIndex and fnColumnIndexToVisible plug-in API
methods for the old API were very useful for transforming the visible
column index to the actual index, and the return. This adds that
capability to the new API.
- Recalculate the "ideal" column sizes for the table. Might want this
after a column visiblity change for example
- Replaces the fnAdjustColumnSizing method.
- This effectively replaces the old fnSetColumnVis method (a shim will
be put in place along with the shim for the rest of the old API). It
has added get abilities, and the option, like the rest of the new API
to work on multiple tables / columns with a single call depending on
the context and selector.
- row options for column selector
- Selectors (table, rows and columns) now held in a single file, sharing
structure. A more unified API is used, with row options also being
allow for columns, through the use of the second parameter for the
columns() method, which will effect how a column function can act upon
rows (for example, the order of the rows when getting data or nodes).
- Dev: tables() is no longer an iterator - using an `iterator()` method
with options which are suitable for the different types of iteration
the API needs.
- We use the cell nodes form the table body in a number of places, and
increasing with the new API, so rather than just storing a reference
to the hidden cells, we should just store a reference to all cells and
use them, cleaning up a number of other areas - in particular
_fnGetTdNodes which is no longer needed
- Should do something similar for _fnGetTrNodes
- Disabled sort classes for the moment as that can be rewritten to be
more efficient. It did use _fnGetTdNodes, but doesn't need to now.
- API fnSetColumnVis and fnUpdate will be broken at the moment, until
merged into the new API.
- rows().nodes() - Get the TR nodes for the selected rows
- rows().data() - Get the data for the selected rows
- columns().header() - Get the header cells for the selected columns
- This also introduces the `iterator` method to the API instance, which
can be used to loop over selected columns / rows, for the context
(tables), returning a flat array / API instance.
- Use variable aliases to allow better compression
- Replace body append code with jQuery code. Much simpiler, and only
a very small performance hit (around 1mS for a draw of 100 records).
- Remove the settings._iDisplayEnd parameter finally, using only
fnDisplayEnd() is needed, and the end point is calculated on-the-fly
when needed (which is not often and it is not expensive). This also
means that the internal method `_fnCalculateEnd` can be dropped
completely.
- Refactoring the empty cell in _fnDraw
- columns() and rows() introduced with their selector components. They
don't have any additional funtionality at this time other than just
being able to selector rows and columns (returning arrays of indexes),
but the principle is now in place, and the additional functions can be
fleshed out.
- Moving to use a work in process branch, as some aspects of DataTables
may break as this work continues, and certainly the files etc are all
in flux
- order() and order.listener() added (to replace fnSort and
fnSortListener) from the old API.
- Note that the name `order` is selected to not conflict with the `sort`
method of the API object, which can be used to order the sort data
held in the collection.
- The `sort()` method is expanded over the abilities of fnSort to allow
multiple different forms of input (column + direction, 1D array, list
of 1D arrays or a 2D array).
- draw() and ajax.reload() can now have `false` passed as their first
(and currently only) parameter, which instructs DataTables to do a
'static' redraw (i.e. not to reset the pagination).
- Previously the master sort and filter functions would perform a draw,
but this was a bit redundant, complex and didn't allow multiple
changes to be queued up before a new draw was performed. The new API
will allow this ability, so we need to allow it in the core as well.
You can now do a sort, and it will be performed internally, but not
actually drawn until the redraw function is called. This makes a full
redraw much simpiler, and has the benefit that a standing redraw is
now relatively trivial since it is all performed in a single place.
- Introducing several methods which will control the ajax aspects of
DataTables through the API:
- ajax.json() - get the last JSON returned from the server
- ajax.reload() - reload from JSON source
- ajax.url( [url] ) - get / set the Ajax URL
- ajax.url( url ).load() - load data from new URL after a set
- Note that this effectively replaces the old fnReloadAjax plug-in which
was quite popular.
- Not yet fully tested - further work required.
- Paging control methods for the new API:
- page() / page(n) - Get / set the current page
- page.info() - Get information about the table's paging state
- page.len() / page.len(n) - Get / set the page length
- Rewrite of core.page.js and core.length.js to be more space efficient.
The functionality is identical to before, but now compresses much
better (796 byte saving). The new paging API methods add only 614
bytes (compressed), so overall a saving of 182 bytes, with the new
functionality added by the new API.
- Start of draw methods for new API:
- draw() - Draw the table. Need this to test the new paging methods
since page() etc do not do a redraw themselves, you must call draw()
when you are ready for the table to be redrawn now.
- tables() is a table selector and iterator that most other API methods
will likely use.
- tables().nodes() gets the selected HTML table nodes.
- Documentation of these functions is rather incomplete. Not yet sure
how to fully document them. Currently thinking of having seperate
documentation, a bit like jQuery, which can be a lot more involved,
rather than building it fromt he doc comments which might get rather
long (they already are!).
- This commit introduces the new Api core, a 'class' which is a data
helper and DataTable control interface. Methods of this class are
designed to be chainable (although it is not manditory - some can
return boolean values if needed).
- The core data helper functions are present in this comment, although
not yet fully documented. That will come as the Api stablises and I'm
happy with the structure.
- There are no table control methods yet - coming soon.
apply that.
- This is much faster than the previous method of using $(this).width()
since there is no longer an invalidation and getComputedStyle
calculation. It just uses the value that is available in style.width,
which might very well be empty (if the style attribute is used with a
width property defined is it not empty).
- This also improves accuracy since it is the original that is restored,
and not the calculated size.
- See http://datatables.net/forums/discussion/14811 for the discussion
for this change.
- Thanks to `krzycho` for the discussion and suggestions.
between table's being reinitialised, so calculating the scrollbar width
every time is a real hit on performance since it needs to manipulate the
DOM. This change ensures that the calculation is performed only once.
- When server-side processing is enabled, fnInitComplete will now be
passed a second parameter, the json returned from the server for that
first draw, matching the Ajax data source with client-side processing
option.
- Full license available here: http://datatables.net/license_mit
- Note that this effectively makes the BSD and GPLv2 licenses that
DataTables is also available under redundant since the MIT is the most
relaxed of these licenses. At some point in the not too distant
future, it would make sense to remove these two licenses and have
DataTables available under only the MIT license.
- Attach an event handler to the window to resize the table. Note that
this isn't debounced - possibly it should be in future(?), but don't
want to add the additional code required if it isn't required. It
seems to function perfectly well for me!
- Unbind needs to unbind by the instance unique reference since there
might be multiple tables listening for the event.
used for the different data types very easily.
- Until now, if you want to use different data for the different data
types (I've called these orthogonal data in relations to DataTables)
you had to specify a function. That's fine, but it seems a rather
clumsy way of just pulling different data out of a source object based
on the type. This method allows the data types to be very easily
defined with an object, allowing the same rules as `render` normally
does (dotted object notation, array notation etc).
- For example:
$(document).ready(function() {
$('#example').dataTable( {
columns: [
{ data: null, render: {
_: 'a',
sort: 'c',
type: 'c',
filter: 'd'
} },
{ data: 'b' }
],
data: [
{ 'a': 1, 'b': 2, 'c': 4, 'd': '1' },
{ 'a': 3, 'b': 4, 'c': 3, 'd': '3' },
{ 'a': 5, 'b': 6, 'c': 2, 'd': '5' },
{ 'a': 7, 'b': 8, 'c': 1, 'd': 'allan' }
]
} );
} );
- Tabbing through a scrolling table the tabindex on the cloned header in
the body part of hte table meant that the browser would focus on those
elements. Fix is to remove the tab index from the clone nodes.
- DataTables 1.9 had 5 different parameters that controlled how Ajax
data was obtained, which with its own naming properties, often mapping
to the jQuery.ajax methods, or otherwise extending them. To hugely
simply and extend the Ajax functionality DataTables has, these five
parameters have now been deprecated and the funtionality provided by
them merged into the new `ajax` parameter.
- Deprecated properties:
- sAjaxSource
- fnServerData
- sAjaxDataProp
- sServerMethod
- fnServerParams
- Note that these parameters are still fully supported and can be used,
but for new projects, `ajax` should be used as they will eventually be
removed (likely DataTables v2 whenever that is, as they are too widely
used to be removed in v1.x).
- Added additional / missing tests for the deprecated properties to
ensure full backwards compatiblity
- The new `ajax` property is fully documented in the doc comments, but
as a summary it can take three forms:
- string - the url to get the data from (i.e. this is the new
sAjaxSource)
- object - maps directly to jQuery.ajax, allowing full control of the
Ajax call (provides the abilities of fnServerParams, sServerMethod,
sAjaxDataProp)
- function - a function so you can get the data your own way
(provides the abilities of fnServerData)
- Added unit tests for the new `ajax` property and doc comment examples
updated to use this property exclusively.
- As of jQuery 1.8 `andSelf` was deprecated in favour of `andBack`.
`andBack` was not available in jQuery <1.8, and I don't want to make
1.8 a requirement yet, so a small workaround requiring two unbind
calls is used to avoid calling `andSelf` or `andBack`.
- jQuery migrate gives a warning about the use of `attr` rather than
`prop`. However, we should really just be using `val` here - much
easier.
- Thread: 13931
object notation.
- Previously if you had an object key that contained a period, it
wouldn't work with `data` or `render` (or rather it would need a
function call to do it manually), since a split was being done on the
periods to reconstruct the Javascript object property chain. Now it is
possible to escape a period, allowing it to be included in the
property name read / set.
- Example:
$('#example').dataTable( {
columns: [
{ data: 'a' },
{ data: 'b\\.c' }
],
data: [
{ 'a': 1, 'b.c': 2 },
{ 'a': 3, 'b.c': 4 },
{ 'a': 5, 'b.c': 6 },
{ 'a': 7, 'b.c': 8 }
]
} );
- As part of completing the planning development for reading data, I've
added support for calling functions from the string defined in `data`
and `render` column options. So you can now do something like:
`render: 'name()'` rather than needing to use an anon function and
calling name() in that. This is useful for cases where you want to
give DataTables an array of Javascript instances, rather than objects
or arrays (see example below). It also fully supports the continuation
of the dotted notation DataTables supports, so you could use
`name().first` if `name()` returns an object. Again to make it easier
than needed to define a function.
- Documentation for `data` and `render` updated to reflect this
abilities
- Unit tests for this still to come
- There is one backwards incompatiblity that should be noted - although
I think this is a real edge case and I just can't see it being an
issue. If before, you had `data:null` without `render` or
`defaultContent` specified, DataTables would have output an empty
cell. Now it will output the original data source object. Can't see
this being an issue since, why would you have a column empty cells? If
this is an issue, then you simply need to add `defaultContent:''` now.
- Example use case, using Javascript instances:
$(document).ready(function() {
var z = function (i) {
this.a = function (set) {
if ( set ) {
return this;
}
return i+'-0';
};
this.b = function (set) {
if ( set ) {
return this;
}
return i+'-1';
};
this.c = function (set) {
if ( set ) {
return this;
}
return i+'-2';
};
this.d = function (set) {
if ( set ) {
return this;
}
return i+'-3';
};
this.e = function (set) {
if ( set ) {
return this;
}
return {
q: i+'-4q',
w: i+'-4w'
};
};
};
window.dataset = [
new z(0),
new z(1),
new z(2),
new z(3),
new z(4),
new z(5)
];
$('#example').dataTable( {
columns: [
{ data: null, /*render: 'a()'*/ },
{ data: 'b()' },
{ data: 'c' },
{ data: 'd()' },
{ data: 'e().q' }
],
data: dataset
} );
} );
- Typically I think setting bDestroy or bRetrieve as default true is a
bad idea as it could lead to more processing of tables than is needed
by mistake, but if set the defaults should be acted upon.
- These are slightly different to the other defaults since the settings
object hasn't been expanded by the point they are checked, so need to
manually check the values.
- When scrolling is enabled, the scrollbar can be placed on the right or
the left of the scrolling container by the browser for rtl layout (of
the current browsers, only Safari appears to place it on the right) -
when placed on the left the padding adjustment that DataTables makes
for the scrollbar area was added to the wrong side.
- To cope with this, the browser compat method (moved to the compat
file) will check for the position of the scrollbar and set a flag so
the scroll draw can adjust the position as needed.
Removed: fnCookieCallback (cookieCallback) - This is now irrelevant since DataTables does not state save in cookies by default.
Removed: sCookiePrefix (cookiePrefix) - This is now irrelevant since DataTables does not state save in cookies by default.
Depreciated: iCookieDuration (cookieDuration) - Since DataTables does not use cookies for state saving by default the name of this parameter is now incorrect. The new parameter `stateDuration` should be used instead, although the old parameter is still supported. It will be removed in the next major version of DataTables.
Update - Performance / Memory: The functions that DataTables uses are not instance based, they are locally scoped, but they were included in the DataTable constructore, which meant that every time you create a new 'instance' of DataTables ($().dataTable()) it would create these functions in that scope again and again. That's completely pointless since we only need them once, so moving them outside the constructor helps both performance and memory (not huge, but very little helps!).
Backwards compatibility issues: The main goal here (other than to use camel-case notation!) is to preserve backwards compatibility. Unfortunately this isn't 100% possible:
- DataTable.defaults.columns has been renamed to be DataTable.defaults.column
- Otherwise it conflicts with aoColumns in the defaults.
Without doubt this is going to be a long process - for example the unit tests and examples need to be completely updated for this change. The JSDoc comments have been updated, so the site should take care of itself for the most part, when released.
In terms of implementation, it is important to note that I have not broken backwards compatibility here - the way it is does is that the current defaults are retained, and a camel-case to Hungarian mapping is automatically generated and then applied to the objects given by the end user. This adds around 0.5K to the size of DataTables, but writing the mapping manually would require at least 3K, and changing DataTables wholesale to camel-case would utterly break backwards compatibility. This is the least 'evil' way to accomplish this. It is important to note that this is a step along the roadmap for DataTables - come v2 Hungarian notation will likely be dropped completely.
One important note to make about this mapping is that if you use camel-case DataTables will copy the value from the camel-case properties to their Hungarian counterparts, so you will end up with additional properties on your source object. As I say, this appears to be to be the least 'evil' option, although still not perfect itself. The challenges of working with legacy software and installs...!
simplify conditions:
!A || (A && (B || C)
really is the same as:
!A || (true && (B || C))
which simplifies to:
!A || (B || C)
which simplifies to:
!A || B || C
- With the introduction of the -pre method in DataTables 1.9, the -asc and -desc sorting functions became more or less redundant since they are simple comparisons (all of the complexity is now in the -pre formatting function). As such the call to the -asc / -desc method is overhead that really isn't needed, and this commit introduces a sort function that doesn't call the -asc / -desc methods, instead just doing the comparison itself. In tests, this relatively simple change leads to a performance improvement of around 15% in all browsers (it also has the side benefit of less operations, so IE8- will be able to sort larger tables before flagging up a slow script warning).
- We can't just remove the sorting method which will call -asc / -desc though since not all sorting plug-ins will have a -pre method. Therefore, for backwards compatiblity the old sort function (albeit updated for the changed variables) is retained. The backwards compatibality code adds around 300 bytes to the library, but this is an unaccounced change, so backwards compatiblity must be retained.
- The old sort method will be removed in v1.11. The -asc and -desc methods are now fully depricated.
- Altered the sorting method to flatten the aaSorting array since the introduction of aDataSort in v1.9 required an extra loop in several locations. The functionality is very useful, but the extra loop can be a bit messy and slightly hit performance, so it is now flattened to be a single array (with object information so it makes sense, rather htan array indexes!).
- Altered the order of sorting when building _aSortData since it was looking up the same variable smultiple times which really wasn't needed.
This is part of a small incremental changes plan for DataTables! There are still a huge number of things to improve in this area, but this is a nice clean up and a nice 15% sorting performance improvement to get us started :-).
Note: _fnColumnOrdering is left in place at the moment, although it may be updated as work progresses on 1.10 with regard to the increased use of column names.
Removed: fnRender - fnRender was depricated in 1.9 and is now being completely removed here. Its always been a bit messy and is now superseded by mRender. The main reason for this is that DataTables use to take an independent copy of the input data source object / array. This is a performance hit and it means we can't do any binding to external objects (for example it makes Knockout integration almost impossible).
Removed: bUseRendered - with fnRender being removed, bUseRendered is irrelevent
Updated: With fnRender being removed we no longer need to take an independent copy of the data source object / array (since DataTables itself isn't ever going to write to it now - fnRender did and the copy was included so we didn't inadvertantly change a developers data source object without them knowing about it. This is no longer a problem, and in fact having it use the same data source object is extremely useful in many cases.
Simplify and improve performance
- Only check once for the presence of any sorting class instead of checking for the 3 individual classes
- Use lastIndexOf(str, 0) instead of indexOf
http://jsperf.com/rep-reg-string/4
Use greedy match regex for replacements
Otherwise, you could have:
"_START_ of _TOTAL_, showing _START_ to _END_"
replaced as:
"1 of 5, showing _START_ to 3"
Tweaks to improve performance
Cache nodes
Restructure to use nextSibling rather than childNodes
(small increase in file size, but may be a slight decrease in minified size)
Fix: Use jQuery html() and text() for HTML data to search method. Much tidier and copes with strict XHTML - downside is that it is a little slower if & is in a data string.
New: Static API method - fnIsDataTable - check if a TABLE node is a DataTable or not
New: Static API method - fnTables - get the DataTables that are initialised on the table (optionally limit to just the visible tables)
Examples update - Tabs and scrolling updated to use the new static fnTables method
Fix: Settings object model was missing the nScrollHead and nScrollFoot properties from the documentation
Fix: Table could conitnually expand when x-scrolling was enabled. This was partly addressed in 6776, but the fix was incomplete as it would still occur on Safari Mac (possibly other browsers as well). This fix is very closely related to 8332 (hence commiting together as they are interdependent). Now use padding right on the header/footer wrapper to provide the overflow scroll ability, but only add it when a scrollbar is present - otherwise the width gets added on and we get the forever expanding table.
Dev: Unit tests - New tests for scrolling to ensure 6776 and 8332 don't occur again
Fix: When using full numbers pagination in IE and clicking upon one of the numbers in the paging control, a Javascript error would occur due to trying to blur an element that was no longer in the DOM
Dev: Removed the "fast lookup" function for data get and set as they weren't really that useful in terms of speed and would require more code to be added to copy with the above change to the error handling for missing objects. Smaller code and virtually no difference in speed. Sold.
New: API: Underscore function updated to use fnGetData rather than its internal function calls. Although slightly more expensive in computation terms, it extends the capacibabites of the underscore function greatly, allowing TD nodes to be the result of the selector as well as TR nodes. So now you can get a column of data with something like: $('#example').dataTable()._('td:nth-child(4)') . Cool :-)
Dev: New internal function called _fnNodeToColumnIndex, adapted from fnGetPosition for reuse.