diff --git a/.gitignore b/.gitignore index af41cfd..00d6eb3 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,8 @@ pkg/* *.gem .bundle *.swp + +vendor/assets/javascripts/.DS_Store +.DS_Store +vendor/.DS_Store +vendor/assets/.DS_Store \ No newline at end of file diff --git a/Gemfile.lock b/Gemfile.lock index 28c0225..b33b5a2 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,111 +1,107 @@ PATH remote: . specs: - simple_datatables (0.1) - meta_search - rails (~> 3.1.0.rc5) - will_paginate (~> 3.0.pre2) - -PATH - remote: jsonify-rails - specs: - jsonify-rails (0.0.6) - actionpack (~> 3.1.0.rc4) - jsonify + rails-datatables (0.3.0) + jsonify-rails + meta_search (~> 1.1.0) + rails (~> 3.1.0) GEM remote: http://rubygems.org/ specs: - actionmailer (3.1.0.rc5) - actionpack (= 3.1.0.rc5) + actionmailer (3.1.1) + actionpack (= 3.1.1) mail (~> 2.3.0) - actionpack (3.1.0.rc5) - activemodel (= 3.1.0.rc5) - activesupport (= 3.1.0.rc5) + actionpack (3.1.1) + activemodel (= 3.1.1) + activesupport (= 3.1.1) builder (~> 3.0.0) erubis (~> 2.7.0) i18n (~> 0.6) - rack (~> 1.3.1) - rack-cache (~> 1.0.2) - rack-mount (~> 0.8.1) - rack-test (~> 0.6.0) - sprockets (~> 2.0.0.beta.12) - activemodel (3.1.0.rc5) - activesupport (= 3.1.0.rc5) - bcrypt-ruby (~> 2.1.4) + rack (~> 1.3.2) + rack-cache (~> 1.1) + rack-mount (~> 0.8.2) + rack-test (~> 0.6.1) + sprockets (~> 2.0.2) + activemodel (3.1.1) + activesupport (= 3.1.1) builder (~> 3.0.0) i18n (~> 0.6) - activerecord (3.1.0.rc5) - activemodel (= 3.1.0.rc5) - activesupport (= 3.1.0.rc5) - arel (~> 2.1.4) + activerecord (3.1.1) + activemodel (= 3.1.1) + activesupport (= 3.1.1) + arel (~> 2.2.1) tzinfo (~> 0.3.29) - activeresource (3.1.0.rc5) - activemodel (= 3.1.0.rc5) - activesupport (= 3.1.0.rc5) - activesupport (3.1.0.rc5) + activeresource (3.1.1) + activemodel (= 3.1.1) + activesupport (= 3.1.1) + activesupport (3.1.1) multi_json (~> 1.0) - arel (2.1.4) - bcrypt-ruby (2.1.4-x86-mingw32) + arel (2.2.1) builder (3.0.0) erubis (2.7.0) - hike (1.2.0) + hike (1.2.1) i18n (0.6.0) - jsonify (0.1.0) + json (1.6.1) + jsonify (0.2.0) + jsonify-rails (0.2.0) + actionpack + jsonify (>= 0.2.0) mail (2.3.0) i18n (>= 0.4.0) mime-types (~> 1.16) treetop (~> 1.4.8) - meta_search (0.5.4) - actionpack (>= 3.0.0.beta4) - activerecord (>= 3.0.0.beta4) - activesupport (>= 3.0.0.beta4) - arel (>= 0.4.0) - mime-types (1.16) - multi_json (1.0.3) - polyglot (0.3.2) - rack (1.3.2) - rack-cache (1.0.2) + meta_search (1.1.1) + actionpack (~> 3.1.0) + activerecord (~> 3.1.0) + activesupport (~> 3.1.0) + polyamorous (~> 0.5.0) + mime-types (1.17.2) + multi_json (1.0.4) + polyamorous (0.5.0) + activerecord (~> 3.0) + polyglot (0.3.3) + rack (1.3.5) + rack-cache (1.1) rack (>= 0.4) - rack-mount (0.8.1) + rack-mount (0.8.3) rack (>= 1.0.0) rack-ssl (1.3.2) rack rack-test (0.6.1) rack (>= 1.0) - rails (3.1.0.rc5) - actionmailer (= 3.1.0.rc5) - actionpack (= 3.1.0.rc5) - activerecord (= 3.1.0.rc5) - activeresource (= 3.1.0.rc5) - activesupport (= 3.1.0.rc5) + rails (3.1.1) + actionmailer (= 3.1.1) + actionpack (= 3.1.1) + activerecord (= 3.1.1) + activeresource (= 3.1.1) + activesupport (= 3.1.1) bundler (~> 1.0) - railties (= 3.1.0.rc5) - railties (3.1.0.rc5) - actionpack (= 3.1.0.rc5) - activesupport (= 3.1.0.rc5) + railties (= 3.1.1) + railties (3.1.1) + actionpack (= 3.1.1) + activesupport (= 3.1.1) rack-ssl (~> 1.3.2) rake (>= 0.8.7) rdoc (~> 3.4) thor (~> 0.14.6) - rake (0.9.2) - rdoc (3.9.1) - sprockets (2.0.0.beta.13) + rake (0.9.2.2) + rdoc (3.11) + json (~> 1.4) + sprockets (2.0.3) hike (~> 1.2) rack (~> 1.0) tilt (~> 1.1, != 1.3.0) thor (0.14.6) - tilt (1.3.2) + tilt (1.3.3) treetop (1.4.10) polyglot polyglot (>= 0.3.1) - tzinfo (0.3.29) - will_paginate (3.0.pre4) + tzinfo (0.3.31) PLATFORMS ruby x86-mingw32 DEPENDENCIES - jsonify-rails! - simple_datatables! + rails-datatables! diff --git a/README.rdoc b/README.rdoc index cb37720..62bdbbb 100644 --- a/README.rdoc +++ b/README.rdoc @@ -1,4 +1,6 @@ -= Simple Datatables += Simple Datatables for Kaminari + +This fork works with kaminari gem! Connects two awesome plugins - Datatables for Jquery and Meta Search together for Rails 3.1 @@ -6,11 +8,11 @@ Connects two awesome plugins - Datatables for Jquery and Meta Search together fo Add the following to your Gemfile to install simple datatables: - gem 'simple_datatables' + gem 'rails_datatables' After bundle install add this line to rails 3.1 assets pipeline and restart server: - //= require simple_datatables + //= require rails_datatables Installation completed. @@ -24,12 +26,12 @@ There are two ways to map awesome Datatables plugin request fields for Rails. This gem provides interface for the second way. To use it you should do the following easy three steps: -Create simple meta_search and will_paginate (optionally) controller action as usual and add ".datatables" format +Create simple meta_search and kaminari (optionally) controller action as usual and add ".datatables" format respond_to :html, :datatables def search - @products = Product.search(params[:search]).paginate(:page => params[:page], :per_page=>params[:per_page]) + @products = Product.search(params[:search]).page(params[:page]).per(params[:per_page]) respond_with @products end @@ -48,6 +50,7 @@ This gem uses: This gem provides integration with: * will_paginate for nice pagination request syntax mapping +* kaminari for pagination as well it works with both so choose either one not both. Gem works only with rails 3.1. @@ -55,7 +58,7 @@ Gem includes datatables library and fnSetFilteringDelay plugin so you haven't in == Pagination -Simple_datatables is compatible with will_paginate. Datatables will provide you "page" and "per_page" request params. +Rails-Datatables is compatible with Kaminari AND Will paginate. Datatables will provide you "page" and "per_page" request params. If you do not use pagination do not forget to save search result to some variable with meta_search relation method: diff --git a/app/views/layouts/application.datatables.jsonify b/app/views/layouts/application.datatables.jsonify index 39cfc71..24360a5 100644 --- a/app/views/layouts/application.datatables.jsonify +++ b/app/views/layouts/application.datatables.jsonify @@ -19,7 +19,11 @@ instance_variables.each do |vn| break; end - if v.respond_to?('total_entries') + if v.respond_to?('total_count') + total_entries = v.total_count + current_page_entries = v.size + break + elsif v.respond_to?('total_entries') total_entries = v.total_entries current_page_entries = v.size break diff --git a/lib/simple_datatables.rb b/lib/rails_datatables.rb similarity index 60% rename from lib/simple_datatables.rb rename to lib/rails_datatables.rb index 7ca7bc7..152fa00 100644 --- a/lib/simple_datatables.rb +++ b/lib/rails_datatables.rb @@ -2,8 +2,8 @@ Mime::Type.register "application/json", :datatables -module SimpleDatatables +module RailsDatatables module Rails - require 'simple_datatables/engine' + require 'rails_datatables/engine' end end diff --git a/lib/simple_datatables/engine.rb b/lib/rails_datatables/engine.rb similarity index 86% rename from lib/simple_datatables/engine.rb rename to lib/rails_datatables/engine.rb index 641ff22..62955bd 100644 --- a/lib/simple_datatables/engine.rb +++ b/lib/rails_datatables/engine.rb @@ -3,7 +3,7 @@ require 'jsonify-rails' require 'meta_search' -module SimpleDatatables +module RailsDatatables module Rails class Engine < ::Rails::Engine end diff --git a/lib/rails_datatables/version.rb b/lib/rails_datatables/version.rb new file mode 100644 index 0000000..f75e89e --- /dev/null +++ b/lib/rails_datatables/version.rb @@ -0,0 +1,3 @@ +module RailsDatatables + VERSION = "0.3.0" +end diff --git a/lib/simple_datatables/version.rb b/lib/simple_datatables/version.rb deleted file mode 100644 index fc325cf..0000000 --- a/lib/simple_datatables/version.rb +++ /dev/null @@ -1,3 +0,0 @@ -module SimpleDatatables - VERSION = "0.1.9" -end diff --git a/rails_datatables.gemspec b/rails_datatables.gemspec new file mode 100644 index 0000000..a11b6d5 --- /dev/null +++ b/rails_datatables.gemspec @@ -0,0 +1,23 @@ +$:.push File.expand_path("../lib", __FILE__) +require "rails_datatables/version" + +Gem::Specification.new do |s| + s.name = "rails_datatables" + s.version = RailsDatatables::VERSION + s.platform = Gem::Platform::RUBY + s.authors = ["Grigory", "Zack"] + s.email = ["sakchai@artellectual.com"] + s.homepage = "http://github.com/artellectual/rails-datatables" + s.summary = %q{Rails datatables to rails mapping using meta_search, will_paginage / Kaminari and jsonify} + s.description = %q{Rails datatables to rails mapping using meta_search, will_paginage / Kaminari and jsonify} + + s.rubyforge_project = "data_table" + + s.files = `git ls-files`.split("\n") + s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) } + s.require_paths = ["lib"] + + s.add_dependency "rails", [">= 3.1.0","< 4.0.0"] + s.add_dependency "meta_search", '~> 1.1.0' + s.add_dependency "jsonify-rails" +end diff --git a/simple_datatables.gemspec b/simple_datatables.gemspec deleted file mode 100644 index c3c997b..0000000 --- a/simple_datatables.gemspec +++ /dev/null @@ -1,24 +0,0 @@ -$:.push File.expand_path("../lib", __FILE__) -require "simple_datatables/version" - -Gem::Specification.new do |s| - s.name = "simple_datatables" - s.version = SimpleDatatables::VERSION - s.platform = Gem::Platform::RUBY - s.authors = ["Grigory"] - s.email = ["grigory@snsk.ru"] - s.homepage = "http://github.com/gryphon/simple_datatables" - s.summary = %q{Simple datatables to rails mapping using meta_search, will_paginage and jsonify} - s.description = %q{Simple datatables to rails mapping using meta_search, will_paginage and jsonify} - - s.rubyforge_project = "data_table" - - s.files = `git ls-files`.split("\n") - s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) } - s.require_paths = ["lib"] - - s.add_dependency "rails", "~> 3.1.0" - s.add_dependency "meta_search", '~> 1.1.0' - s.add_dependency "jsonify-rails" - -end diff --git a/vendor/assets/javascripts/jquery.dataTables.js b/vendor/assets/javascripts/jquery.dataTables.js new file mode 100644 index 0000000..a295d17 --- /dev/null +++ b/vendor/assets/javascripts/jquery.dataTables.js @@ -0,0 +1,7440 @@ +/* + * File: jquery.dataTables.js + * Version: 1.8.2 + * Description: Paginate, search and sort HTML tables + * Author: Allan Jardine (www.sprymedia.co.uk) + * Created: 28/3/2008 + * Language: Javascript + * License: GPL v2 or BSD 3 point style + * Project: Mtaala + * Contact: allan.jardine@sprymedia.co.uk + * + * Copyright 2008-2011 Allan Jardine, all rights reserved. + * + * This source file is free software, under either the GPL v2 license or a + * BSD style license, as supplied with this software. + * + * This source file is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details. + * + * For details please refer to: http://www.datatables.net + */ + +/* + * When considering jsLint, we need to allow eval() as it it is used for reading cookies + */ +/*jslint evil: true, undef: true, browser: true */ +/*globals $, jQuery,_fnExternApiFunc,_fnInitialise,_fnInitComplete,_fnLanguageProcess,_fnAddColumn,_fnColumnOptions,_fnAddData,_fnCreateTr,_fnGatherData,_fnBuildHead,_fnDrawHead,_fnDraw,_fnReDraw,_fnAjaxUpdate,_fnAjaxParameters,_fnAjaxUpdateDraw,_fnServerParams,_fnAddOptionsHtml,_fnFeatureHtmlTable,_fnScrollDraw,_fnAdjustColumnSizing,_fnFeatureHtmlFilter,_fnFilterComplete,_fnFilterCustom,_fnFilterColumn,_fnFilter,_fnBuildSearchArray,_fnBuildSearchRow,_fnFilterCreateSearch,_fnDataToSearch,_fnSort,_fnSortAttachListener,_fnSortingClasses,_fnFeatureHtmlPaginate,_fnPageChange,_fnFeatureHtmlInfo,_fnUpdateInfo,_fnFeatureHtmlLength,_fnFeatureHtmlProcessing,_fnProcessingDisplay,_fnVisibleToColumnIndex,_fnColumnIndexToVisible,_fnNodeToDataIndex,_fnVisbleColumns,_fnCalculateEnd,_fnConvertToWidth,_fnCalculateColumnWidths,_fnScrollingWidthAdjust,_fnGetWidestNode,_fnGetMaxLenString,_fnStringToCss,_fnArrayCmp,_fnDetectType,_fnSettingsFromNode,_fnGetDataMaster,_fnGetTrNodes,_fnGetTdNodes,_fnEscapeRegex,_fnDeleteIndex,_fnReOrderIndex,_fnColumnOrdering,_fnLog,_fnClearTable,_fnSaveState,_fnLoadState,_fnCreateCookie,_fnReadCookie,_fnDetectHeader,_fnGetUniqueThs,_fnScrollBarWidth,_fnApplyToChildren,_fnMap,_fnGetRowData,_fnGetCellData,_fnSetCellData,_fnGetObjectDataFn,_fnSetObjectDataFn*/ + +(function($, window, document) { + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Section - DataTables variables + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + + /* + * Variable: dataTableSettings + * Purpose: Store the settings for each dataTables instance + * Scope: jQuery.fn + */ + $.fn.dataTableSettings = []; + var _aoSettings = $.fn.dataTableSettings; /* Short reference for fast internal lookup */ + + /* + * Variable: dataTableExt + * Purpose: Container for customisable parts of DataTables + * Scope: jQuery.fn + */ + $.fn.dataTableExt = {}; + var _oExt = $.fn.dataTableExt; + + + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Section - DataTables extensible objects + * + * The _oExt object is used to provide an area where user defined plugins can be + * added to DataTables. The following properties of the object are used: + * oApi - Plug-in API functions + * aTypes - Auto-detection of types + * oSort - Sorting functions used by DataTables (based on the type) + * oPagination - Pagination functions for different input styles + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + + /* + * Variable: sVersion + * Purpose: Version string for plug-ins to check compatibility + * Scope: jQuery.fn.dataTableExt + * Notes: Allowed format is a.b.c.d.e where: + * a:int, b:int, c:int, d:string(dev|beta), e:int. d and e are optional + */ + _oExt.sVersion = "1.8.2"; + + /* + * Variable: sErrMode + * Purpose: How should DataTables report an error. Can take the value 'alert' or 'throw' + * Scope: jQuery.fn.dataTableExt + */ + _oExt.sErrMode = "alert"; + + /* + * Variable: iApiIndex + * Purpose: Index for what 'this' index API functions should use + * Scope: jQuery.fn.dataTableExt + */ + _oExt.iApiIndex = 0; + + /* + * Variable: oApi + * Purpose: Container for plugin API functions + * Scope: jQuery.fn.dataTableExt + */ + _oExt.oApi = { }; + + /* + * Variable: aFiltering + * Purpose: Container for plugin filtering functions + * Scope: jQuery.fn.dataTableExt + */ + _oExt.afnFiltering = [ ]; + + /* + * Variable: aoFeatures + * Purpose: Container for plugin function functions + * Scope: jQuery.fn.dataTableExt + * Notes: Array of objects with the following parameters: + * fnInit: Function for initialisation of Feature. Takes oSettings and returns node + * cFeature: Character that will be matched in sDom - case sensitive + * sFeature: Feature name - just for completeness :-) + */ + _oExt.aoFeatures = [ ]; + + /* + * Variable: ofnSearch + * Purpose: Container for custom filtering functions + * Scope: jQuery.fn.dataTableExt + * Notes: This is an object (the name should match the type) for custom filtering function, + * which can be used for live DOM checking or formatted text filtering + */ + _oExt.ofnSearch = { }; + + /* + * Variable: afnSortData + * Purpose: Container for custom sorting data source functions + * Scope: jQuery.fn.dataTableExt + * Notes: Array (associative) of functions which is run prior to a column of this + * 'SortDataType' being sorted upon. + * Function input parameters: + * object:oSettings- DataTables settings object + * int:iColumn - Target column number + * Return value: Array of data which exactly matched the full data set size for the column to + * be sorted upon + */ + _oExt.afnSortData = [ ]; + + /* + * Variable: oStdClasses + * Purpose: Storage for the various classes that DataTables uses + * Scope: jQuery.fn.dataTableExt + */ + _oExt.oStdClasses = { + /* Two buttons buttons */ + "sPagePrevEnabled": "paginate_enabled_previous", + "sPagePrevDisabled": "paginate_disabled_previous", + "sPageNextEnabled": "paginate_enabled_next", + "sPageNextDisabled": "paginate_disabled_next", + "sPageJUINext": "", + "sPageJUIPrev": "", + + /* Full numbers paging buttons */ + "sPageButton": "paginate_button", + "sPageButtonActive": "paginate_active", + "sPageButtonStaticDisabled": "paginate_button paginate_button_disabled", + "sPageFirst": "first", + "sPagePrevious": "previous", + "sPageNext": "next", + "sPageLast": "last", + + /* Striping classes */ + "sStripeOdd": "odd", + "sStripeEven": "even", + + /* Empty row */ + "sRowEmpty": "dataTables_empty", + + /* Features */ + "sWrapper": "dataTables_wrapper", + "sFilter": "dataTables_filter", + "sInfo": "dataTables_info", + "sPaging": "dataTables_paginate paging_", /* Note that the type is postfixed */ + "sLength": "dataTables_length", + "sProcessing": "dataTables_processing", + + /* Sorting */ + "sSortAsc": "sorting_asc", + "sSortDesc": "sorting_desc", + "sSortable": "sorting", /* Sortable in both directions */ + "sSortableAsc": "sorting_asc_disabled", + "sSortableDesc": "sorting_desc_disabled", + "sSortableNone": "sorting_disabled", + "sSortColumn": "sorting_", /* Note that an int is postfixed for the sorting order */ + "sSortJUIAsc": "", + "sSortJUIDesc": "", + "sSortJUI": "", + "sSortJUIAscAllowed": "", + "sSortJUIDescAllowed": "", + "sSortJUIWrapper": "", + "sSortIcon": "", + + /* Scrolling */ + "sScrollWrapper": "dataTables_scroll", + "sScrollHead": "dataTables_scrollHead", + "sScrollHeadInner": "dataTables_scrollHeadInner", + "sScrollBody": "dataTables_scrollBody", + "sScrollFoot": "dataTables_scrollFoot", + "sScrollFootInner": "dataTables_scrollFootInner", + + /* Misc */ + "sFooterTH": "" + }; + + /* + * Variable: oJUIClasses + * Purpose: Storage for the various classes that DataTables uses - jQuery UI suitable + * Scope: jQuery.fn.dataTableExt + */ + _oExt.oJUIClasses = { + /* Two buttons buttons */ + "sPagePrevEnabled": "fg-button ui-button ui-state-default ui-corner-left", + "sPagePrevDisabled": "fg-button ui-button ui-state-default ui-corner-left ui-state-disabled", + "sPageNextEnabled": "fg-button ui-button ui-state-default ui-corner-right", + "sPageNextDisabled": "fg-button ui-button ui-state-default ui-corner-right ui-state-disabled", + "sPageJUINext": "ui-icon ui-icon-circle-arrow-e", + "sPageJUIPrev": "ui-icon ui-icon-circle-arrow-w", + + /* Full numbers paging buttons */ + "sPageButton": "fg-button ui-button ui-state-default", + "sPageButtonActive": "fg-button ui-button ui-state-default ui-state-disabled", + "sPageButtonStaticDisabled": "fg-button ui-button ui-state-default ui-state-disabled", + "sPageFirst": "first ui-corner-tl ui-corner-bl", + "sPagePrevious": "previous", + "sPageNext": "next", + "sPageLast": "last ui-corner-tr ui-corner-br", + + /* Striping classes */ + "sStripeOdd": "odd", + "sStripeEven": "even", + + /* Empty row */ + "sRowEmpty": "dataTables_empty", + + /* Features */ + "sWrapper": "dataTables_wrapper", + "sFilter": "dataTables_filter", + "sInfo": "dataTables_info", + "sPaging": "dataTables_paginate fg-buttonset ui-buttonset fg-buttonset-multi "+ + "ui-buttonset-multi paging_", /* Note that the type is postfixed */ + "sLength": "dataTables_length", + "sProcessing": "dataTables_processing", + + /* Sorting */ + "sSortAsc": "ui-state-default", + "sSortDesc": "ui-state-default", + "sSortable": "ui-state-default", + "sSortableAsc": "ui-state-default", + "sSortableDesc": "ui-state-default", + "sSortableNone": "ui-state-default", + "sSortColumn": "sorting_", /* Note that an int is postfixed for the sorting order */ + "sSortJUIAsc": "css_right ui-icon ui-icon-triangle-1-n", + "sSortJUIDesc": "css_right ui-icon ui-icon-triangle-1-s", + "sSortJUI": "css_right ui-icon ui-icon-carat-2-n-s", + "sSortJUIAscAllowed": "css_right ui-icon ui-icon-carat-1-n", + "sSortJUIDescAllowed": "css_right ui-icon ui-icon-carat-1-s", + "sSortJUIWrapper": "DataTables_sort_wrapper", + "sSortIcon": "DataTables_sort_icon", + + /* Scrolling */ + "sScrollWrapper": "dataTables_scroll", + "sScrollHead": "dataTables_scrollHead ui-state-default", + "sScrollHeadInner": "dataTables_scrollHeadInner", + "sScrollBody": "dataTables_scrollBody", + "sScrollFoot": "dataTables_scrollFoot ui-state-default", + "sScrollFootInner": "dataTables_scrollFootInner", + + /* Misc */ + "sFooterTH": "ui-state-default" + }; + + /* + * Variable: oPagination + * Purpose: Container for the various type of pagination that dataTables supports + * Scope: jQuery.fn.dataTableExt + */ + _oExt.oPagination = { + /* + * Variable: two_button + * Purpose: Standard two button (forward/back) pagination + * Scope: jQuery.fn.dataTableExt.oPagination + */ + "two_button": { + /* + * Function: oPagination.two_button.fnInit + * Purpose: Initialise dom elements required for pagination with forward/back buttons only + * Returns: - + * Inputs: object:oSettings - dataTables settings object + * node:nPaging - the DIV which contains this pagination control + * function:fnCallbackDraw - draw function which must be called on update + */ + "fnInit": function ( oSettings, nPaging, fnCallbackDraw ) + { + var nPrevious, nNext, nPreviousInner, nNextInner; + + /* Store the next and previous elements in the oSettings object as they can be very + * usful for automation - particularly testing + */ + if ( !oSettings.bJUI ) + { + nPrevious = document.createElement( 'div' ); + nNext = document.createElement( 'div' ); + } + else + { + nPrevious = document.createElement( 'a' ); + nNext = document.createElement( 'a' ); + + nNextInner = document.createElement('span'); + nNextInner.className = oSettings.oClasses.sPageJUINext; + nNext.appendChild( nNextInner ); + + nPreviousInner = document.createElement('span'); + nPreviousInner.className = oSettings.oClasses.sPageJUIPrev; + nPrevious.appendChild( nPreviousInner ); + } + + nPrevious.className = oSettings.oClasses.sPagePrevDisabled; + nNext.className = oSettings.oClasses.sPageNextDisabled; + + nPrevious.title = oSettings.oLanguage.oPaginate.sPrevious; + nNext.title = oSettings.oLanguage.oPaginate.sNext; + + nPaging.appendChild( nPrevious ); + nPaging.appendChild( nNext ); + + $(nPrevious).bind( 'click.DT', function() { + if ( oSettings.oApi._fnPageChange( oSettings, "previous" ) ) + { + /* Only draw when the page has actually changed */ + fnCallbackDraw( oSettings ); + } + } ); + + $(nNext).bind( 'click.DT', function() { + if ( oSettings.oApi._fnPageChange( oSettings, "next" ) ) + { + fnCallbackDraw( oSettings ); + } + } ); + + /* Take the brutal approach to cancelling text selection */ + $(nPrevious).bind( 'selectstart.DT', function () { return false; } ); + $(nNext).bind( 'selectstart.DT', function () { return false; } ); + + /* ID the first elements only */ + if ( oSettings.sTableId !== '' && typeof oSettings.aanFeatures.p == "undefined" ) + { + nPaging.setAttribute( 'id', oSettings.sTableId+'_paginate' ); + nPrevious.setAttribute( 'id', oSettings.sTableId+'_previous' ); + nNext.setAttribute( 'id', oSettings.sTableId+'_next' ); + } + }, + + /* + * Function: oPagination.two_button.fnUpdate + * Purpose: Update the two button pagination at the end of the draw + * Returns: - + * Inputs: object:oSettings - dataTables settings object + * function:fnCallbackDraw - draw function to call on page change + */ + "fnUpdate": function ( oSettings, fnCallbackDraw ) + { + if ( !oSettings.aanFeatures.p ) + { + return; + } + + /* Loop over each instance of the pager */ + var an = oSettings.aanFeatures.p; + for ( var i=0, iLen=an.length ; i= (iPages - iPageCountHalf)) + { + iStartButton = iPages - iPageCount + 1; + iEndButton = iPages; + } + else + { + iStartButton = iCurrentPage - Math.ceil(iPageCount / 2) + 1; + iEndButton = iStartButton + iPageCount - 1; + } + } + } + + /* Build the dynamic list */ + for ( i=iStartButton ; i<=iEndButton ; i++ ) + { + if ( iCurrentPage != i ) + { + sList += ''+i+''; + } + else + { + sList += ''+i+''; + } + } + + /* Loop over each instance of the pager */ + var an = oSettings.aanFeatures.p; + var anButtons, anStatic, nPaginateList; + var fnClick = function(e) { + /* Use the information in the element to jump to the required page */ + var iTarget = (this.innerHTML * 1) - 1; + oSettings._iDisplayStart = iTarget * oSettings._iDisplayLength; + fnCallbackDraw( oSettings ); + e.preventDefault(); + }; + var fnFalse = function () { return false; }; + + for ( i=0, iLen=an.length ; i y) ? 1 : 0)); + }, + + "string-desc": function ( a, b ) + { + if ( typeof a != 'string' ) { a = ''; } + if ( typeof b != 'string' ) { b = ''; } + var x = a.toLowerCase(); + var y = b.toLowerCase(); + return ((x < y) ? 1 : ((x > y) ? -1 : 0)); + }, + + + /* + * html sorting (ignore html tags) + */ + "html-asc": function ( a, b ) + { + var x = a.replace( /<.*?>/g, "" ).toLowerCase(); + var y = b.replace( /<.*?>/g, "" ).toLowerCase(); + return ((x < y) ? -1 : ((x > y) ? 1 : 0)); + }, + + "html-desc": function ( a, b ) + { + var x = a.replace( /<.*?>/g, "" ).toLowerCase(); + var y = b.replace( /<.*?>/g, "" ).toLowerCase(); + return ((x < y) ? 1 : ((x > y) ? -1 : 0)); + }, + + + /* + * date sorting + */ + "date-asc": function ( a, b ) + { + var x = Date.parse( a ); + var y = Date.parse( b ); + + if ( isNaN(x) || x==="" ) + { + x = Date.parse( "01/01/1970 00:00:00" ); + } + if ( isNaN(y) || y==="" ) + { + y = Date.parse( "01/01/1970 00:00:00" ); + } + + return x - y; + }, + + "date-desc": function ( a, b ) + { + var x = Date.parse( a ); + var y = Date.parse( b ); + + if ( isNaN(x) || x==="" ) + { + x = Date.parse( "01/01/1970 00:00:00" ); + } + if ( isNaN(y) || y==="" ) + { + y = Date.parse( "01/01/1970 00:00:00" ); + } + + return y - x; + }, + + + /* + * numerical sorting + */ + "numeric-asc": function ( a, b ) + { + var x = (a=="-" || a==="") ? 0 : a*1; + var y = (b=="-" || b==="") ? 0 : b*1; + return x - y; + }, + + "numeric-desc": function ( a, b ) + { + var x = (a=="-" || a==="") ? 0 : a*1; + var y = (b=="-" || b==="") ? 0 : b*1; + return y - x; + } + }; + + + /* + * Variable: aTypes + * Purpose: Container for the various type of type detection that dataTables supports + * Scope: jQuery.fn.dataTableExt + * Notes: The functions in this array are expected to parse a string to see if it is a data + * type that it recognises. If so then the function should return the name of the type (a + * corresponding sort function should be defined!), if the type is not recognised then the + * function should return null such that the parser and move on to check the next type. + * Note that ordering is important in this array - the functions are processed linearly, + * starting at index 0. + * Note that the input for these functions is always a string! It cannot be any other data + * type + */ + _oExt.aTypes = [ + /* + * Function: - + * Purpose: Check to see if a string is numeric + * Returns: string:'numeric' or null + * Inputs: mixed:sText - string to check + */ + function ( sData ) + { + /* Allow zero length strings as a number */ + if ( typeof sData == 'number' ) + { + return 'numeric'; + } + else if ( typeof sData != 'string' ) + { + return null; + } + + var sValidFirstChars = "0123456789-"; + var sValidChars = "0123456789."; + var Char; + var bDecimal = false; + + /* Check for a valid first char (no period and allow negatives) */ + Char = sData.charAt(0); + if (sValidFirstChars.indexOf(Char) == -1) + { + return null; + } + + /* Check all the other characters are valid */ + for ( var i=1 ; i') != -1 ) + { + return 'html'; + } + return null; + } + ]; + + /* + * Function: fnVersionCheck + * Purpose: Check a version string against this version of DataTables. Useful for plug-ins + * Returns: bool:true -this version of DataTables is greater or equal to the required version + * false -this version of DataTales is not suitable + * Inputs: string:sVersion - the version to check against. May be in the following formats: + * "a", "a.b" or "a.b.c" + * Notes: This function will only check the first three parts of a version string. It is + * assumed that beta and dev versions will meet the requirements. This might change in future + */ + _oExt.fnVersionCheck = function( sVersion ) + { + /* This is cheap, but very effective */ + var fnZPad = function (Zpad, count) + { + while(Zpad.length < count) { + Zpad += '0'; + } + return Zpad; + }; + var aThis = _oExt.sVersion.split('.'); + var aThat = sVersion.split('.'); + var sThis = '', sThat = ''; + + for ( var i=0, iLen=aThat.length ; i= parseInt(sThat, 10); + }; + + /* + * Variable: _oExternConfig + * Purpose: Store information for DataTables to access globally about other instances + * Scope: jQuery.fn.dataTableExt + */ + _oExt._oExternConfig = { + /* int:iNextUnique - next unique number for an instance */ + "iNextUnique": 0 + }; + + + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Section - DataTables prototype + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + + /* + * Function: dataTable + * Purpose: DataTables information + * Returns: - + * Inputs: object:oInit - initialisation options for the table + */ + $.fn.dataTable = function( oInit ) + { + /* + * Function: classSettings + * Purpose: Settings container function for all 'class' properties which are required + * by dataTables + * Returns: - + * Inputs: - + */ + function classSettings () + { + this.fnRecordsTotal = function () + { + if ( this.oFeatures.bServerSide ) { + return parseInt(this._iRecordsTotal, 10); + } else { + return this.aiDisplayMaster.length; + } + }; + + this.fnRecordsDisplay = function () + { + if ( this.oFeatures.bServerSide ) { + return parseInt(this._iRecordsDisplay, 10); + } else { + return this.aiDisplay.length; + } + }; + + this.fnDisplayEnd = function () + { + if ( this.oFeatures.bServerSide ) { + if ( this.oFeatures.bPaginate === false || this._iDisplayLength == -1 ) { + return this._iDisplayStart+this.aiDisplay.length; + } else { + return Math.min( this._iDisplayStart+this._iDisplayLength, + this._iRecordsDisplay ); + } + } else { + return this._iDisplayEnd; + } + }; + + /* + * Variable: oInstance + * Purpose: The DataTables object for this table + * Scope: jQuery.dataTable.classSettings + */ + this.oInstance = null; + + /* + * Variable: sInstance + * Purpose: Unique idendifier for each instance of the DataTables object + * Scope: jQuery.dataTable.classSettings + */ + this.sInstance = null; + + /* + * Variable: oFeatures + * Purpose: Indicate the enablement of key dataTable features + * Scope: jQuery.dataTable.classSettings + */ + this.oFeatures = { + "bPaginate": true, + "bLengthChange": true, + "bFilter": true, + "bSort": true, + "bInfo": true, + "bAutoWidth": true, + "bProcessing": false, + "bSortClasses": true, + "bStateSave": false, + "bServerSide": false, + "bDeferRender": false + }; + + /* + * Variable: oScroll + * Purpose: Container for scrolling options + * Scope: jQuery.dataTable.classSettings + */ + this.oScroll = { + "sX": "", + "sXInner": "", + "sY": "", + "bCollapse": false, + "bInfinite": false, + "iLoadGap": 100, + "iBarWidth": 0, + "bAutoCss": true + }; + + /* + * Variable: aanFeatures + * Purpose: Array referencing the nodes which are used for the features + * Scope: jQuery.dataTable.classSettings + * Notes: The parameters of this object match what is allowed by sDom - i.e. + * 'l' - Length changing + * 'f' - Filtering input + * 't' - The table! + * 'i' - Information + * 'p' - Pagination + * 'r' - pRocessing + */ + this.aanFeatures = []; + + /* + * Variable: oLanguage + * Purpose: Store the language strings used by dataTables + * Scope: jQuery.dataTable.classSettings + * Notes: The words in the format _VAR_ are variables which are dynamically replaced + * by javascript + */ + this.oLanguage = { + "sProcessing": "Processing...", + "sLengthMenu": "Show _MENU_ entries", + "sZeroRecords": "No matching records found", + "sEmptyTable": "No data available in table", + "sLoadingRecords": "Loading...", + "sInfo": "Showing _START_ to _END_ of _TOTAL_ entries", + "sInfoEmpty": "Showing 0 to 0 of 0 entries", + "sInfoFiltered": "(filtered from _MAX_ total entries)", + "sInfoPostFix": "", + "sInfoThousands": ",", + "sSearch": "Search:", + "sUrl": "", + "oPaginate": { + "sFirst": "First", + "sPrevious": "Previous", + "sNext": "Next", + "sLast": "Last" + }, + "fnInfoCallback": null + }; + + /* + * Variable: aoData + * Purpose: Store data information + * Scope: jQuery.dataTable.classSettings + * Notes: This is an array of objects with the following parameters: + * int: _iId - internal id for tracking + * array: _aData - internal data - used for sorting / filtering etc + * node: nTr - display node + * array node: _anHidden - hidden TD nodes + * string: _sRowStripe + */ + this.aoData = []; + + /* + * Variable: aiDisplay + * Purpose: Array of indexes which are in the current display (after filtering etc) + * Scope: jQuery.dataTable.classSettings + */ + this.aiDisplay = []; + + /* + * Variable: aiDisplayMaster + * Purpose: Array of indexes for display - no filtering + * Scope: jQuery.dataTable.classSettings + */ + this.aiDisplayMaster = []; + + /* + * Variable: aoColumns + * Purpose: Store information about each column that is in use + * Scope: jQuery.dataTable.classSettings + */ + this.aoColumns = []; + + /* + * Variable: aoHeader + * Purpose: Store information about the table's header + * Scope: jQuery.dataTable.classSettings + */ + this.aoHeader = []; + + /* + * Variable: aoFooter + * Purpose: Store information about the table's footer + * Scope: jQuery.dataTable.classSettings + */ + this.aoFooter = []; + + /* + * Variable: iNextId + * Purpose: Store the next unique id to be used for a new row + * Scope: jQuery.dataTable.classSettings + */ + this.iNextId = 0; + + /* + * Variable: asDataSearch + * Purpose: Search data array for regular expression searching + * Scope: jQuery.dataTable.classSettings + */ + this.asDataSearch = []; + + /* + * Variable: oPreviousSearch + * Purpose: Store the previous search incase we want to force a re-search + * or compare the old search to a new one + * Scope: jQuery.dataTable.classSettings + */ + this.oPreviousSearch = { + "sSearch": "", + "bRegex": false, + "bSmart": true + }; + + /* + * Variable: aoPreSearchCols + * Purpose: Store the previous search for each column + * Scope: jQuery.dataTable.classSettings + */ + this.aoPreSearchCols = []; + + /* + * Variable: aaSorting + * Purpose: Sorting information + * Scope: jQuery.dataTable.classSettings + * Notes: Index 0 - column number + * Index 1 - current sorting direction + * Index 2 - index of asSorting for this column + */ + this.aaSorting = [ [0, 'asc', 0] ]; + + /* + * Variable: aaSortingFixed + * Purpose: Sorting information that is always applied + * Scope: jQuery.dataTable.classSettings + */ + this.aaSortingFixed = null; + + /* + * Variable: asStripeClasses + * Purpose: Classes to use for the striping of a table + * Scope: jQuery.dataTable.classSettings + */ + this.asStripeClasses = []; + + /* + * Variable: asDestroyStripes + * Purpose: If restoring a table - we should restore its striping classes as well + * Scope: jQuery.dataTable.classSettings + */ + this.asDestroyStripes = []; + + /* + * Variable: sDestroyWidth + * Purpose: If restoring a table - we should restore its width + * Scope: jQuery.dataTable.classSettings + */ + this.sDestroyWidth = 0; + + /* + * Variable: fnRowCallback + * Purpose: Call this function every time a row is inserted (draw) + * Scope: jQuery.dataTable.classSettings + */ + this.fnRowCallback = null; + + /* + * Variable: fnHeaderCallback + * Purpose: Callback function for the header on each draw + * Scope: jQuery.dataTable.classSettings + */ + this.fnHeaderCallback = null; + + /* + * Variable: fnFooterCallback + * Purpose: Callback function for the footer on each draw + * Scope: jQuery.dataTable.classSettings + */ + this.fnFooterCallback = null; + + /* + * Variable: aoDrawCallback + * Purpose: Array of callback functions for draw callback functions + * Scope: jQuery.dataTable.classSettings + * Notes: Each array element is an object with the following parameters: + * function:fn - function to call + * string:sName - name callback (feature). useful for arranging array + */ + this.aoDrawCallback = []; + + /* + * Variable: fnPreDrawCallback + * Purpose: Callback function for just before the table is redrawn. A return of false + * will be used to cancel the draw. + * Scope: jQuery.dataTable.classSettings + */ + this.fnPreDrawCallback = null; + + /* + * Variable: fnInitComplete + * Purpose: Callback function for when the table has been initialised + * Scope: jQuery.dataTable.classSettings + */ + this.fnInitComplete = null; + + /* + * Variable: sTableId + * Purpose: Cache the table ID for quick access + * Scope: jQuery.dataTable.classSettings + */ + this.sTableId = ""; + + /* + * Variable: nTable + * Purpose: Cache the table node for quick access + * Scope: jQuery.dataTable.classSettings + */ + this.nTable = null; + + /* + * Variable: nTHead + * Purpose: Permanent ref to the thead element + * Scope: jQuery.dataTable.classSettings + */ + this.nTHead = null; + + /* + * Variable: nTFoot + * Purpose: Permanent ref to the tfoot element - if it exists + * Scope: jQuery.dataTable.classSettings + */ + this.nTFoot = null; + + /* + * Variable: nTBody + * Purpose: Permanent ref to the tbody element + * Scope: jQuery.dataTable.classSettings + */ + this.nTBody = null; + + /* + * Variable: nTableWrapper + * Purpose: Cache the wrapper node (contains all DataTables controlled elements) + * Scope: jQuery.dataTable.classSettings + */ + this.nTableWrapper = null; + + /* + * Variable: bDeferLoading + * Purpose: Indicate if when using server-side processing the loading of data + * should be deferred until the second draw + * Scope: jQuery.dataTable.classSettings + */ + this.bDeferLoading = false; + + /* + * Variable: bInitialised + * Purpose: Indicate if all required information has been read in + * Scope: jQuery.dataTable.classSettings + */ + this.bInitialised = false; + + /* + * Variable: aoOpenRows + * Purpose: Information about open rows + * Scope: jQuery.dataTable.classSettings + * Notes: Has the parameters 'nTr' and 'nParent' + */ + this.aoOpenRows = []; + + /* + * Variable: sDom + * Purpose: Dictate the positioning that the created elements will take + * Scope: jQuery.dataTable.classSettings + * Notes: + * The following options are allowed: + * 'l' - Length changing + * 'f' - Filtering input + * 't' - The table! + * 'i' - Information + * 'p' - Pagination + * 'r' - pRocessing + * The following constants are allowed: + * 'H' - jQueryUI theme "header" classes + * 'F' - jQueryUI theme "footer" classes + * The following syntax is expected: + * '<' and '>' - div elements + * '<"class" and '>' - div with a class + * Examples: + * '<"wrapper"flipt>', 'ip>' + */ + this.sDom = 'lfrtip'; + + /* + * Variable: sPaginationType + * Purpose: Note which type of sorting should be used + * Scope: jQuery.dataTable.classSettings + */ + this.sPaginationType = "two_button"; + + /* + * Variable: iCookieDuration + * Purpose: The cookie duration (for bStateSave) in seconds - default 2 hours + * Scope: jQuery.dataTable.classSettings + */ + this.iCookieDuration = 60 * 60 * 2; + + /* + * Variable: sCookiePrefix + * Purpose: The cookie name prefix + * Scope: jQuery.dataTable.classSettings + */ + this.sCookiePrefix = "SpryMedia_DataTables_"; + + /* + * Variable: fnCookieCallback + * Purpose: Callback function for cookie creation + * Scope: jQuery.dataTable.classSettings + */ + this.fnCookieCallback = null; + + /* + * Variable: aoStateSave + * Purpose: Array of callback functions for state saving + * Scope: jQuery.dataTable.classSettings + * Notes: Each array element is an object with the following parameters: + * function:fn - function to call. Takes two parameters, oSettings and the JSON string to + * save that has been thus far created. Returns a JSON string to be inserted into a + * json object (i.e. '"param": [ 0, 1, 2]') + * string:sName - name of callback + */ + this.aoStateSave = []; + + /* + * Variable: aoStateLoad + * Purpose: Array of callback functions for state loading + * Scope: jQuery.dataTable.classSettings + * Notes: Each array element is an object with the following parameters: + * function:fn - function to call. Takes two parameters, oSettings and the object stored. + * May return false to cancel state loading. + * string:sName - name of callback + */ + this.aoStateLoad = []; + + /* + * Variable: oLoadedState + * Purpose: State that was loaded from the cookie. Useful for back reference + * Scope: jQuery.dataTable.classSettings + */ + this.oLoadedState = null; + + /* + * Variable: sAjaxSource + * Purpose: Source url for AJAX data for the table + * Scope: jQuery.dataTable.classSettings + */ + this.sAjaxSource = null; + + /* + * Variable: sAjaxDataProp + * Purpose: Property from a given object from which to read the table data from. This can + * be an empty string (when not server-side processing), in which case it is + * assumed an an array is given directly. + * Scope: jQuery.dataTable.classSettings + */ + this.sAjaxDataProp = 'aaData'; + + /* + * Variable: bAjaxDataGet + * Purpose: Note if draw should be blocked while getting data + * Scope: jQuery.dataTable.classSettings + */ + this.bAjaxDataGet = true; + + /* + * Variable: jqXHR + * Purpose: The last jQuery XHR object that was used for server-side data gathering. + * This can be used for working with the XHR information in one of the callbacks + * Scope: jQuery.dataTable.classSettings + */ + this.jqXHR = null; + + /* + * Variable: fnServerData + * Purpose: Function to get the server-side data - can be overruled by the developer + * Scope: jQuery.dataTable.classSettings + */ + this.fnServerData = function ( url, data, callback, settings ) { + settings.jqXHR = $.ajax( { + "url": url, + "data": data, + "success": function (json) { + $(settings.oInstance).trigger('xhr', settings); + callback( json ); + }, + "dataType": "json", + "cache": false, + "error": function (xhr, error, thrown) { + if ( error == "parsererror" ) { + alert( "DataTables warning: JSON data from server could not be parsed. "+ + "This is caused by a JSON formatting error." ); + } + } + } ); + }; + + /* + * Variable: aoServerParams + * Purpose: Functions which are called prior to sending an Ajax request so extra parameters + * can easily be sent to the server + * Scope: jQuery.dataTable.classSettings + * Notes: Each array element is an object with the following parameters: + * function:fn - function to call + * string:sName - name callback - useful for knowing where it came from (plugin etc) + */ + this.aoServerParams = []; + + /* + * Variable: fnFormatNumber + * Purpose: Format numbers for display + * Scope: jQuery.dataTable.classSettings + */ + this.fnFormatNumber = function ( iIn ) + { + if ( iIn < 1000 ) + { + /* A small optimisation for what is likely to be the vast majority of use cases */ + return iIn; + } + else + { + var s=(iIn+""), a=s.split(""), out="", iLen=s.length; + + for ( var i=0 ; i