lanes 0.1.2 → 0.1.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (399) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +19 -0
  3. data/client/lanes/access/Extension.coffee +19 -0
  4. data/client/lanes/access/LoginDialog.coffee +47 -0
  5. data/client/lanes/access/Roles.coffee +88 -0
  6. data/client/lanes/access/User.coffee +72 -0
  7. data/client/lanes/access/index.js +5 -0
  8. data/client/lanes/access/login-dialog.html +16 -0
  9. data/client/lanes/access/screens/user-management/GridUserEditor.coffee +25 -0
  10. data/client/lanes/access/screens/user-management/UserManagement.coffee +24 -0
  11. data/client/lanes/access/screens/user-management/grid-popover-editor.html +33 -0
  12. data/client/lanes/access/screens/user-management/index.js +3 -0
  13. data/client/lanes/access/screens/user-management/index.scss +7 -0
  14. data/client/lanes/access/screens/user-management/screen.html +7 -0
  15. data/client/lanes/{components/enabled.scss.erb → access/styles.scss} +0 -0
  16. data/{lib/lanes/command/templates/client/components → client/lanes/access/views}/.gitkeep +0 -0
  17. data/client/lanes/components/Base.coffee +3 -4
  18. data/client/lanes/components/enabled.js.erb +2 -0
  19. data/client/lanes/components/grid/Editor.coffee +1 -1
  20. data/client/lanes/components/grid/Grid.coffee +26 -27
  21. data/client/lanes/components/grid/{_index.scss → styles.scss} +0 -0
  22. data/client/lanes/components/grid/template.html +1 -1
  23. data/client/lanes/components/grid/vendor/dataTables.scroller.js +119 -42
  24. data/client/lanes/components/grid/vendor/jquery.dataTables.js +984 -526
  25. data/client/lanes/components/modal/ModalDialog.coffee +25 -4
  26. data/client/lanes/components/modal/styles.scss +19 -0
  27. data/client/lanes/components/modal/template.html +2 -2
  28. data/client/lanes/components/multi-select/MultiSelect.coffee +46 -0
  29. data/client/lanes/components/popover/PopOver.coffee +1 -1
  30. data/client/lanes/components/popover/styles.scss +2 -0
  31. data/client/lanes/components/{radio_group → radio-group}/RadioGroup.coffee +12 -23
  32. data/client/lanes/components/radio-group/index.js +1 -0
  33. data/client/lanes/components/radio-group/styles.scss +1 -0
  34. data/client/lanes/components/record-finder/Clause.coffee +38 -0
  35. data/client/lanes/components/record-finder/Dialog.coffee +45 -0
  36. data/client/lanes/components/record-finder/RecordFinder.coffee +55 -0
  37. data/client/lanes/components/{record_finder/clause.skr → record-finder/clause.html} +7 -5
  38. data/client/lanes/components/record-finder/config.json +3 -0
  39. data/client/lanes/components/{record_finder/dialog.skr → record-finder/dialog.html} +0 -0
  40. data/client/lanes/components/{record_finder/field.skr → record-finder/field.html} +1 -1
  41. data/client/lanes/components/record-finder/index.js +4 -0
  42. data/client/lanes/{styles/components/record-finder.scss → components/record-finder/styles.scss} +22 -20
  43. data/client/lanes/components/select-field/SelectField.coffee +62 -0
  44. data/client/lanes/components/{select_field → select-field}/index.js +0 -0
  45. data/client/lanes/components/{select_field/_index.scss → select-field/styles.scss} +0 -0
  46. data/client/lanes/extension/EarlyExtensions.js.erb +3 -3
  47. data/client/lanes/extension/Extensions.coffee +4 -1
  48. data/client/lanes/extension/LateLoaded.js.erb +3 -3
  49. data/client/lanes/index.js +2 -2
  50. data/client/lanes/index.scss.erb +30 -0
  51. data/client/lanes/lib/MakeBaseClass.coffee +20 -19
  52. data/client/lanes/lib/ModuleSupport.coffee +1 -1
  53. data/client/lanes/lib/results.coffee +1 -9
  54. data/client/lanes/lib/utilFunctions.coffee +56 -10
  55. data/client/lanes/models/Base.coffee +57 -116
  56. data/client/lanes/models/ChangeMonitor.coffee +29 -0
  57. data/client/lanes/models/ChangeSet.coffee +3 -3
  58. data/client/lanes/models/Collection.coffee +36 -4
  59. data/client/lanes/models/ModelAssociations.coffee +118 -0
  60. data/client/lanes/models/PubSub.coffee +5 -5
  61. data/client/lanes/models/Query.coffee +37 -27
  62. data/client/lanes/models/Sync.coffee +1 -1
  63. data/client/lanes/models/index.js +1 -0
  64. data/client/lanes/screens/Base.coffee +5 -8
  65. data/client/lanes/screens/ChangeListener.coffee +6 -3
  66. data/client/lanes/{models/Screens.coffee → screens/Definitions.coffee} +22 -9
  67. data/client/lanes/screens/Instance.coffee +22 -22
  68. data/client/lanes/screens/Router.coffee +1 -3
  69. data/client/lanes/screens/all.js.erb +3 -0
  70. data/client/lanes/screens/index.js +6 -1
  71. data/client/lanes/screens/{screen-definitions.js.erb → register.js.erb} +3 -3
  72. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/_alerts.scss +0 -0
  73. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/_badges.scss +0 -0
  74. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/_breadcrumbs.scss +0 -0
  75. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/_button-groups.scss +0 -0
  76. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/_buttons.scss +0 -0
  77. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/_carousel.scss +0 -0
  78. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/_close.scss +0 -0
  79. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/_code.scss +0 -0
  80. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/_component-animations.scss +0 -0
  81. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/_dropdowns.scss +0 -0
  82. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/_forms.scss +0 -0
  83. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/_glyphicons.scss +0 -0
  84. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/_grid.scss +0 -0
  85. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/_input-groups.scss +0 -0
  86. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/_jumbotron.scss +0 -0
  87. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/_labels.scss +0 -0
  88. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/_list-group.scss +0 -0
  89. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/_media.scss +0 -0
  90. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/_mixins.scss +0 -0
  91. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/_modals.scss +0 -0
  92. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/_navbar.scss +0 -0
  93. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/_navs.scss +0 -0
  94. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/_normalize.scss +0 -0
  95. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/_pager.scss +0 -0
  96. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/_pagination.scss +0 -0
  97. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/_panels.scss +0 -0
  98. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/_popovers.scss +0 -0
  99. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/_print.scss +0 -0
  100. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/_progress-bars.scss +0 -0
  101. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/_responsive-embed.scss +0 -0
  102. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/_responsive-utilities.scss +0 -0
  103. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/_scaffolding.scss +0 -0
  104. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/_tables.scss +0 -0
  105. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/_theme.scss +0 -0
  106. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/_thumbnails.scss +0 -0
  107. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/_tooltip.scss +0 -0
  108. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/_type.scss +0 -0
  109. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/_utilities.scss +0 -0
  110. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/_variables.scss +0 -0
  111. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/_wells.scss +0 -0
  112. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/mixins/_alerts.scss +0 -0
  113. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/mixins/_background-variant.scss +0 -0
  114. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/mixins/_border-radius.scss +0 -0
  115. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/mixins/_buttons.scss +0 -0
  116. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/mixins/_center-block.scss +0 -0
  117. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/mixins/_clearfix.scss +0 -0
  118. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/mixins/_forms.scss +0 -0
  119. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/mixins/_gradients.scss +0 -0
  120. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/mixins/_grid-framework.scss +0 -0
  121. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/mixins/_grid.scss +0 -0
  122. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/mixins/_hide-text.scss +0 -0
  123. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/mixins/_image.scss +0 -0
  124. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/mixins/_labels.scss +0 -0
  125. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/mixins/_list-group.scss +0 -0
  126. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/mixins/_nav-divider.scss +0 -0
  127. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/mixins/_nav-vertical-align.scss +0 -0
  128. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/mixins/_opacity.scss +0 -0
  129. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/mixins/_pagination.scss +0 -0
  130. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/mixins/_panels.scss +0 -0
  131. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/mixins/_progress-bar.scss +0 -0
  132. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/mixins/_reset-filter.scss +0 -0
  133. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/mixins/_resize.scss +0 -0
  134. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/mixins/_responsive-visibility.scss +0 -0
  135. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/mixins/_size.scss +0 -0
  136. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/mixins/_tab-focus.scss +0 -0
  137. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/mixins/_table-row.scss +0 -0
  138. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/mixins/_text-emphasis.scss +0 -0
  139. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/mixins/_text-overflow.scss +0 -0
  140. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/mixins/_vendor-prefixes.scss +0 -0
  141. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/old/_alerts.scss +0 -0
  142. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/old/_badges.scss +0 -0
  143. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/old/_breadcrumbs.scss +0 -0
  144. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/old/_button-groups.scss +0 -0
  145. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/old/_buttons.scss +0 -0
  146. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/old/_carousel.scss +0 -0
  147. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/old/_close.scss +0 -0
  148. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/old/_code.scss +0 -0
  149. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/old/_component-animations.scss +0 -0
  150. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/old/_dropdowns.scss +0 -0
  151. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/old/_forms.scss +0 -0
  152. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/old/_glyphicons.scss +0 -0
  153. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/old/_grid.scss +0 -0
  154. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/old/_input-groups.scss +0 -0
  155. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/old/_jumbotron.scss +0 -0
  156. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/old/_labels.scss +0 -0
  157. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/old/_list-group.scss +0 -0
  158. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/old/_media.scss +0 -0
  159. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/old/_mixins.scss +0 -0
  160. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/old/_modals.scss +0 -0
  161. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/old/_navbar.scss +0 -0
  162. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/old/_navs.scss +0 -0
  163. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/old/_normalize.scss +0 -0
  164. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/old/_pager.scss +0 -0
  165. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/old/_pagination.scss +0 -0
  166. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/old/_panels.scss +0 -0
  167. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/old/_popovers.scss +0 -0
  168. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/old/_print.scss +0 -0
  169. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/old/_progress-bars.scss +0 -0
  170. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/old/_responsive-embed.scss +0 -0
  171. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/old/_responsive-utilities.scss +0 -0
  172. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/old/_scaffolding.scss +0 -0
  173. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/old/_tables.scss +0 -0
  174. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/old/_theme.scss +0 -0
  175. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/old/_thumbnails.scss +0 -0
  176. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/old/_tooltip.scss +0 -0
  177. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/old/_type.scss +0 -0
  178. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/old/_utilities.scss +0 -0
  179. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/old/_variables.scss +0 -0
  180. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/old/_wells.scss +0 -0
  181. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/old/bootstrap.scss +0 -0
  182. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/old/mixins/_alerts.scss +0 -0
  183. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/old/mixins/_background-variant.scss +0 -0
  184. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/old/mixins/_border-radius.scss +0 -0
  185. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/old/mixins/_buttons.scss +0 -0
  186. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/old/mixins/_center-block.scss +0 -0
  187. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/old/mixins/_clearfix.scss +0 -0
  188. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/old/mixins/_forms.scss +0 -0
  189. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/old/mixins/_gradients.scss +0 -0
  190. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/old/mixins/_grid-framework.scss +0 -0
  191. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/old/mixins/_grid.scss +0 -0
  192. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/old/mixins/_hide-text.scss +0 -0
  193. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/old/mixins/_image.scss +0 -0
  194. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/old/mixins/_labels.scss +0 -0
  195. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/old/mixins/_list-group.scss +0 -0
  196. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/old/mixins/_nav-divider.scss +0 -0
  197. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/old/mixins/_nav-vertical-align.scss +0 -0
  198. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/old/mixins/_opacity.scss +0 -0
  199. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/old/mixins/_pagination.scss +0 -0
  200. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/old/mixins/_panels.scss +0 -0
  201. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/old/mixins/_progress-bar.scss +0 -0
  202. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/old/mixins/_reset-filter.scss +0 -0
  203. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/old/mixins/_resize.scss +0 -0
  204. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/old/mixins/_responsive-visibility.scss +0 -0
  205. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/old/mixins/_size.scss +0 -0
  206. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/old/mixins/_tab-focus.scss +0 -0
  207. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/old/mixins/_table-row.scss +0 -0
  208. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/old/mixins/_text-emphasis.scss +0 -0
  209. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/old/mixins/_text-overflow.scss +0 -0
  210. data/client/lanes/styles/{vendor/bootstrap → bootstrap}/old/mixins/_vendor-prefixes.scss +0 -0
  211. data/client/lanes/styles/{vendor/bootstrap-custom-grid.scss → bootstrap-custom-grid.scss} +0 -0
  212. data/client/lanes/styles/{vendor/bootstrap-custom-modals.scss → bootstrap-custom-modals.scss} +0 -0
  213. data/client/lanes/styles/bootstrap.scss +71 -0
  214. data/client/lanes/styles/{vendor/dataTables.scss → dataTables.scss} +0 -0
  215. data/client/lanes/styles/fonts.scss +9 -20
  216. data/client/lanes/vendor/packaged.js +27 -25
  217. data/client/lanes/views/Base.coffee +47 -34
  218. data/client/lanes/views/FormBindings.coffee +10 -9
  219. data/client/lanes/views/Helpers.coffee +14 -16
  220. data/client/lanes/views/ModelObserver.coffee +4 -4
  221. data/client/lanes/views/ModelUpdate.coffee +5 -2
  222. data/client/lanes/views/PubSub.coffee +1 -1
  223. data/client/lanes/views/Viewport.coffee +8 -78
  224. data/client/lanes/views/_button.html +1 -1
  225. data/client/lanes/views/_toolbar.html +21 -25
  226. data/client/lanes/views/model-update.html +7 -5
  227. data/client/lanes/workspace/ActiveScreensSwitcher.coffee +6 -12
  228. data/client/lanes/workspace/Extension.coffee +3 -0
  229. data/client/lanes/workspace/Layout.coffee +13 -9
  230. data/client/lanes/workspace/Navbar.coffee +2 -18
  231. data/client/lanes/workspace/Pages.coffee +13 -14
  232. data/client/lanes/workspace/ScreensMenu.coffee +9 -18
  233. data/client/lanes/workspace/UIState.coffee +78 -0
  234. data/client/lanes/workspace/WorkspaceView.coffee +4 -1
  235. data/client/lanes/workspace/index.js +0 -3
  236. data/client/lanes/workspace/navbar.html +0 -4
  237. data/client/lanes/workspace/pages.html +1 -1
  238. data/client/lanes/workspace/styles/changes-notification.scss +57 -0
  239. data/client/lanes/{styles → workspace/styles}/forms.scss +0 -0
  240. data/client/lanes/workspace/styles/header.scss +42 -0
  241. data/client/lanes/{styles → workspace/styles}/keybindings.scss +0 -0
  242. data/client/lanes/workspace/styles/layout.scss +209 -0
  243. data/client/lanes/workspace/styles/screens.scss +67 -0
  244. data/client/lanes/workspace/styles/tabs.scss +147 -0
  245. data/client/lanes/workspace/styles/toolbar.scss +4 -0
  246. data/client/lanes/workspace/styles.scss +20 -0
  247. data/docs/model.md +39 -7
  248. data/docs/todo-example-part-1.md +7 -7
  249. data/docs/view.md +57 -40
  250. data/lib/lanes/access/authentication_provider.rb +59 -0
  251. data/lib/lanes/access/config/routes.rb +26 -0
  252. data/lib/lanes/access/config/screens.rb +16 -0
  253. data/lib/lanes/access/db/migrate/20140615031600_create_lanes_users.rb +12 -0
  254. data/lib/lanes/access/extension.rb +40 -0
  255. data/lib/lanes/access/locked_fields.rb +43 -0
  256. data/lib/lanes/access/role.rb +60 -0
  257. data/lib/lanes/access/role_collection.rb +76 -0
  258. data/lib/lanes/access/roles/administrator.rb +39 -0
  259. data/lib/lanes/access/roles/support.rb +15 -0
  260. data/lib/lanes/access/track_modifications.rb +48 -0
  261. data/lib/lanes/access/user.rb +128 -0
  262. data/lib/lanes/access/version.rb +5 -0
  263. data/lib/lanes/access.rb +51 -0
  264. data/lib/lanes/api/helper_methods.rb +2 -2
  265. data/lib/lanes/api/javascript_processor.rb +3 -3
  266. data/lib/lanes/api/null_authentication_provider.rb +1 -1
  267. data/lib/lanes/api/pub_sub.rb +3 -3
  268. data/lib/lanes/api/request_wrapper.rb +1 -1
  269. data/lib/lanes/api/root.rb +1 -2
  270. data/lib/lanes/api/sprockets_extension.rb +6 -4
  271. data/lib/lanes/api/test_specs.rb +2 -8
  272. data/lib/lanes/command/app.rb +30 -12
  273. data/lib/lanes/command/db.rb +3 -0
  274. data/lib/lanes/command/generate_model.rb +4 -4
  275. data/lib/lanes/command/generate_screen.rb +12 -10
  276. data/lib/lanes/command/generate_view.rb +12 -9
  277. data/lib/lanes/command/named_command.rb +7 -5
  278. data/lib/lanes/command/server.rb +1 -1
  279. data/lib/lanes/command.rb +2 -5
  280. data/lib/lanes/components.rb +1 -1
  281. data/lib/lanes/concerns/queries.rb +1 -1
  282. data/lib/lanes/concerns/set_attribute_data.rb +5 -7
  283. data/lib/lanes/db.rb +5 -4
  284. data/lib/lanes/extension/definition.rb +95 -0
  285. data/lib/lanes/extension.rb +34 -69
  286. data/lib/lanes/guard_tasks.rb +2 -2
  287. data/lib/lanes/screen.rb +8 -0
  288. data/lib/lanes/spec_helper.rb +1 -37
  289. data/lib/lanes/version.rb +1 -1
  290. data/lib/lanes/workspace/extension.rb +28 -0
  291. data/lib/lanes/workspace.rb +7 -0
  292. data/npm-build/package.json +2 -2
  293. data/spec/api/javascript_processor_spec.rb +1 -1
  294. data/spec/lanes/components/grid/GridSpec.coffee +31 -0
  295. data/{lib/lanes/command/templates/client/views → spec/lanes/helpers}/.gitkeep +0 -0
  296. data/spec/{helpers → lanes/helpers}/jasmine-matchers.js +0 -0
  297. data/spec/{helpers → lanes/helpers}/lanes-helpers.coffee +2 -4
  298. data/spec/lanes/helpers/mock-ajax.js +576 -0
  299. data/spec/lanes/models/BaseSpec.coffee +24 -37
  300. data/spec/lanes/models/CollectionSpec.coffee +15 -2
  301. data/spec/lanes/models/ModelAssociationsSpec.coffee +51 -0
  302. data/spec/lanes/views/BaseSpec.coffee +14 -14
  303. data/spec/server/command_spec.rb +39 -0
  304. data/spec/{concerns → server/concerns}/api_path_spec.rb +1 -1
  305. data/spec/{concerns → server/concerns}/association_extensions_spec.rb +1 -2
  306. data/spec/{concerns → server/concerns}/attr_accessor_with_default_spec.rb +0 -0
  307. data/spec/{concerns → server/concerns}/export_associations_spec.rb +1 -2
  308. data/spec/{concerns → server/concerns}/export_methods_spec.rb +1 -3
  309. data/spec/{concerns → server/concerns}/export_scope_spec.rb +2 -2
  310. data/spec/{concerns → server/concerns}/exported_limits_spec.rb +1 -2
  311. data/spec/{concerns → server/concerns}/pub_sub_spec.rb +1 -1
  312. data/spec/{concerns → server/concerns}/set_attribute_data_spec.rb +1 -1
  313. data/spec/{configuration_spec.rb → server/configuration_spec.rb} +1 -1
  314. data/spec/{helpers → server}/minitest_assertions.rb +1 -1
  315. data/spec/{numbers_spec.rb → server/numbers_spec.rb} +1 -2
  316. data/{lib/lanes/testing_models.rb → spec/server/spec_helper.rb} +17 -3
  317. data/spec/{strings_spec.rb → server/strings_spec.rb} +1 -1
  318. data/templates/Gemfile +6 -0
  319. data/{lib/lanes/command/templates → templates}/Guardfile +0 -0
  320. data/templates/Rakefile +2 -0
  321. data/templates/client/Extension.coffee +7 -0
  322. data/templates/client/Router.coffee +4 -0
  323. data/{lib/lanes/command/templates/public → templates/client/components}/.gitkeep +0 -0
  324. data/templates/client/components/Component.coffee +1 -0
  325. data/{lib/lanes/command/templates → templates}/client/index.js +1 -0
  326. data/templates/client/models/BaseModel.coffee +5 -0
  327. data/{lib/lanes/command/templates → templates}/client/models/Model.coffee +2 -3
  328. data/{lib/lanes/command/templates → templates}/client/screens/Screen.coffee +6 -1
  329. data/{lib/lanes/command/templates → templates}/client/screens/index.js +0 -0
  330. data/{lib/lanes/command/templates → templates}/client/screens/layout.html +0 -0
  331. data/{lib/lanes/command/templates → templates}/client/screens/styles.scss +1 -2
  332. data/{lib/lanes/command/templates → templates}/client/styles.scss +0 -0
  333. data/{spec/helpers → templates/client/views}/.gitkeep +0 -0
  334. data/templates/client/views/BaseView.coffee +5 -0
  335. data/templates/client/views/View.coffee +10 -0
  336. data/{lib/lanes/command/templates → templates}/client/views/template.html +0 -0
  337. data/{lib/lanes/command/templates → templates}/config/database.yml +0 -0
  338. data/{lib/lanes/command/templates → templates}/config/lanes.rb +0 -0
  339. data/{lib/lanes/command/templates → templates}/config/routes.rb +0 -0
  340. data/templates/config/screen.rb +12 -0
  341. data/{lib/lanes/command/templates → templates}/config.ru +1 -1
  342. data/{lib/lanes/command/templates → templates}/db/create_table_migration.rb +1 -1
  343. data/{lib/lanes/command/templates → templates}/gitignore +1 -0
  344. data/templates/lib/namespace/base_model.rb +11 -0
  345. data/{lib/lanes/command/templates → templates}/lib/namespace/extension.rb +3 -3
  346. data/{lib/lanes/command/templates → templates}/lib/namespace/model.rb +1 -1
  347. data/templates/lib/namespace/version.rb +3 -0
  348. data/templates/lib/namespace.rb +14 -0
  349. data/templates/public/.gitkeep +0 -0
  350. data/templates/spec/client/Screen.coffee +5 -0
  351. data/templates/spec/client/helpers/ClientHelpers.coffee +5 -0
  352. data/templates/spec/client/models/ModelSpec.coffee +5 -0
  353. data/templates/spec/client/views/ViewSpec.coffee +5 -0
  354. data/{lib/lanes/command/templates → templates}/spec/fixtures/namespace/model.yml +0 -0
  355. data/{lib/lanes/command/templates/spec/namespace → templates/spec/server}/model_spec.rb +2 -2
  356. data/{lib/lanes/command/templates/spec/spec_helper.rb → templates/spec/server/spec_helpers.rb} +3 -2
  357. data/views/index.erb +5 -4
  358. data/views/specs.erb +2 -1
  359. metadata +273 -238
  360. data/client/lanes/components/grid/vendor/dataTables.bootstrap.js +0 -156
  361. data/client/lanes/components/grid/vendor/datatables.responsive.js +0 -666
  362. data/client/lanes/components/modal/_index.scss +0 -20
  363. data/client/lanes/components/popover/_index.scss +0 -1
  364. data/client/lanes/components/record_finder/RecordFinder.coffee +0 -143
  365. data/client/lanes/components/select_field/SelectField.coffee +0 -87
  366. data/client/lanes/extension/GlAccounts.coffee +0 -9
  367. data/client/lanes/minimal.js +0 -11
  368. data/client/lanes/minimal.scss.erb +0 -12
  369. data/client/lanes/styles/components/all.scss +0 -6
  370. data/client/lanes/styles/components/changes-notification.scss +0 -44
  371. data/client/lanes/styles/components/suggest.scss +0 -266
  372. data/client/lanes/styles/index.css +0 -4
  373. data/client/lanes/styles/layout.scss +0 -272
  374. data/client/lanes/styles/screens.scss +0 -66
  375. data/client/lanes/styles/tabs.scss +0 -148
  376. data/client/lanes/styles/vendor/bootstrap.scss +0 -74
  377. data/client/lanes/workspace.scss.erb +0 -29
  378. data/client/lanes-complete.js +0 -3
  379. data/client/lanes-workspace.scss.erb +0 -21
  380. data/db/migrate/20140615031600_create_hip_users.rb +0 -17
  381. data/lib/lanes/command/templates/Gemfile +0 -9
  382. data/lib/lanes/command/templates/Rakefile +0 -2
  383. data/lib/lanes/command/templates/client/Extension.coffee +0 -5
  384. data/lib/lanes/command/templates/client/components/Component.coffee +0 -1
  385. data/lib/lanes/command/templates/client/models/BaseModel.coffee +0 -5
  386. data/lib/lanes/command/templates/client/views/BaseView.coffee +0 -5
  387. data/lib/lanes/command/templates/client/views/View.coffee +0 -7
  388. data/lib/lanes/command/templates/config/screen.rb +0 -8
  389. data/lib/lanes/command/templates/lib/namespace/base_model.rb +0 -9
  390. data/lib/lanes/command/templates/lib/namespace/version.rb +0 -3
  391. data/lib/lanes/command/templates/lib/namespace.rb +0 -12
  392. data/lib/lanes/command/templates/spec/client/Screen.coffee +0 -7
  393. data/lib/lanes/command/templates/spec/client/models/ModelSpec.coffee +0 -5
  394. data/lib/lanes/command/templates/spec/client/views/ViewSpec.coffee +0 -5
  395. data/lib/lanes/db/migration_helpers.rb +0 -178
  396. data/public/javascripts/jasmine_examples/Player.js +0 -22
  397. data/public/javascripts/jasmine_examples/Song.js +0 -7
  398. data/spec/command_spec.rb +0 -49
  399. data/spec/helpers/jasmine-jquery.js +0 -813
@@ -1,11 +1,11 @@
1
- /*! DataTables 1.10.0
1
+ /*! DataTables 1.10.4
2
2
  * ©2008-2014 SpryMedia Ltd - datatables.net/license
3
3
  */
4
4
 
5
5
  /**
6
6
  * @summary DataTables
7
7
  * @description Paginate, search and order HTML tables
8
- * @version 1.10.0
8
+ * @version 1.10.4
9
9
  * @file jquery.dataTables.js
10
10
  * @author SpryMedia Ltd (www.sprymedia.co.uk)
11
11
  * @contact www.sprymedia.co.uk/contact
@@ -22,7 +22,7 @@
22
22
  */
23
23
 
24
24
  /*jslint evil: true, undef: true, browser: true */
25
- /*globals $,require,jQuery,define,_selector_run,_selector_opts,_selector_first,_selector_row_indexes,_ext,_Api,_api_register,_api_registerPlural,_re_new_lines,_re_html,_re_formatted_numeric,_re_escape_regex,_empty,_intVal,_numToDecimal,_isNumber,_isHtml,_htmlNumeric,_pluck,_pluck_order,_range,_stripHtml,_unique,_fnBuildAjax,_fnAjaxUpdate,_fnAjaxParameters,_fnAjaxUpdateDraw,_fnAjaxDataSrc,_fnAddColumn,_fnColumnOptions,_fnAdjustColumnSizing,_fnVisibleToColumnIndex,_fnColumnIndexToVisible,_fnVisbleColumns,_fnGetColumns,_fnColumnTypes,_fnApplyColumnDefs,_fnHungarianMap,_fnCamelToHungarian,_fnLanguageCompat,_fnBrowserDetect,_fnAddData,_fnAddTr,_fnNodeToDataIndex,_fnNodeToColumnIndex,_fnGetCellData,_fnSetCellData,_fnSplitObjNotation,_fnGetObjectDataFn,_fnSetObjectDataFn,_fnGetDataMaster,_fnClearTable,_fnDeleteIndex,_fnInvalidateRow,_fnGetRowElements,_fnCreateTr,_fnBuildHead,_fnDrawHead,_fnDraw,_fnReDraw,_fnAddOptionsHtml,_fnDetectHeader,_fnGetUniqueThs,_fnFeatureHtmlFilter,_fnFilterComplete,_fnFilterCustom,_fnFilterColumn,_fnFilter,_fnFilterCreateSearch,_fnEscapeRegex,_fnFilterData,_fnFeatureHtmlInfo,_fnUpdateInfo,_fnInfoMacros,_fnInitialise,_fnInitComplete,_fnLengthChange,_fnFeatureHtmlLength,_fnFeatureHtmlPaginate,_fnPageChange,_fnFeatureHtmlProcessing,_fnProcessingDisplay,_fnFeatureHtmlTable,_fnScrollDraw,_fnApplyToChildren,_fnCalculateColumnWidths,_fnThrottle,_fnConvertToWidth,_fnScrollingWidthAdjust,_fnGetWidestNode,_fnGetMaxLenString,_fnStringToCss,_fnScrollBarWidth,_fnSortFlatten,_fnSort,_fnSortAria,_fnSortListener,_fnSortAttachListener,_fnSortingClasses,_fnSortData,_fnSaveState,_fnLoadState,_fnSettingsFromNode,_fnLog,_fnMap,_fnBindAction,_fnCallbackReg,_fnCallbackFire,_fnLengthOverflow,_fnRenderer,_fnDataSource,_fnRowAttributes*/
25
+ /*globals $,require,jQuery,define,_selector_run,_selector_opts,_selector_first,_selector_row_indexes,_ext,_Api,_api_register,_api_registerPlural,_re_new_lines,_re_html,_re_formatted_numeric,_re_escape_regex,_empty,_intVal,_numToDecimal,_isNumber,_isHtml,_htmlNumeric,_pluck,_pluck_order,_range,_stripHtml,_unique,_fnBuildAjax,_fnAjaxUpdate,_fnAjaxParameters,_fnAjaxUpdateDraw,_fnAjaxDataSrc,_fnAddColumn,_fnColumnOptions,_fnAdjustColumnSizing,_fnVisibleToColumnIndex,_fnColumnIndexToVisible,_fnVisbleColumns,_fnGetColumns,_fnColumnTypes,_fnApplyColumnDefs,_fnHungarianMap,_fnCamelToHungarian,_fnLanguageCompat,_fnBrowserDetect,_fnAddData,_fnAddTr,_fnNodeToDataIndex,_fnNodeToColumnIndex,_fnGetCellData,_fnSetCellData,_fnSplitObjNotation,_fnGetObjectDataFn,_fnSetObjectDataFn,_fnGetDataMaster,_fnClearTable,_fnDeleteIndex,_fnInvalidate,_fnGetRowElements,_fnCreateTr,_fnBuildHead,_fnDrawHead,_fnDraw,_fnReDraw,_fnAddOptionsHtml,_fnDetectHeader,_fnGetUniqueThs,_fnFeatureHtmlFilter,_fnFilterComplete,_fnFilterCustom,_fnFilterColumn,_fnFilter,_fnFilterCreateSearch,_fnEscapeRegex,_fnFilterData,_fnFeatureHtmlInfo,_fnUpdateInfo,_fnInfoMacros,_fnInitialise,_fnInitComplete,_fnLengthChange,_fnFeatureHtmlLength,_fnFeatureHtmlPaginate,_fnPageChange,_fnFeatureHtmlProcessing,_fnProcessingDisplay,_fnFeatureHtmlTable,_fnScrollDraw,_fnApplyToChildren,_fnCalculateColumnWidths,_fnThrottle,_fnConvertToWidth,_fnScrollingWidthAdjust,_fnGetWidestNode,_fnGetMaxLenString,_fnStringToCss,_fnScrollBarWidth,_fnSortFlatten,_fnSort,_fnSortAria,_fnSortListener,_fnSortAttachListener,_fnSortingClasses,_fnSortData,_fnSaveState,_fnLoadState,_fnSettingsFromNode,_fnLog,_fnMap,_fnBindAction,_fnCallbackReg,_fnCallbackFire,_fnLengthOverflow,_fnRenderer,_fnDataSource,_fnRowAttributes*/
26
26
 
27
27
  (/** @lends <global> */function( window, document, undefined ) {
28
28
 
@@ -38,7 +38,6 @@
38
38
  factory( require( 'jquery' ) );
39
39
  }
40
40
  else if ( jQuery && !jQuery.fn.dataTable ) {
41
-
42
41
  // Define using browser globals otherwise
43
42
  // Prevent multiple instantiations if the script is loaded twice
44
43
  factory( jQuery );
@@ -106,7 +105,8 @@
106
105
  var _re_dic = {};
107
106
  var _re_new_lines = /[\r\n]/g;
108
107
  var _re_html = /<.*?>/g;
109
- var _re_date_start = /^[\d\+\-a-zA-Z]/;
108
+ var _re_date_start = /^[\w\+\-]/;
109
+ var _re_date_end = /[\w\+\-]$/;
110
110
 
111
111
  // Escape regular expression special characters
112
112
  var _re_escape_regex = new RegExp( '(\\' + [ '/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\', '$', '^', '-' ].join('|\\') + ')', 'g' );
@@ -117,7 +117,7 @@
117
117
 
118
118
 
119
119
  var _empty = function ( d ) {
120
- return !d || d === '-' ? true : false;
120
+ return !d || d === true || d === '-' ? true : false;
121
121
  };
122
122
 
123
123
 
@@ -133,7 +133,7 @@
133
133
  if ( ! _re_dic[ decimalPoint ] ) {
134
134
  _re_dic[ decimalPoint ] = new RegExp( _fnEscapeRegex( decimalPoint ), 'g' );
135
135
  }
136
- return typeof num === 'string' ?
136
+ return typeof num === 'string' && decimalPoint !== '.' ?
137
137
  num.replace( /\./g, '' ).replace( _re_dic[ decimalPoint ], '.' ) :
138
138
  num;
139
139
  };
@@ -150,13 +150,13 @@
150
150
  d = d.replace( _re_formatted_numeric, '' );
151
151
  }
152
152
 
153
- return !d || d==='-' || (!isNaN( parseFloat(d) ) && isFinite( d ));
153
+ return _empty( d ) || (!isNaN( parseFloat(d) ) && isFinite( d ));
154
154
  };
155
155
 
156
156
 
157
157
  // A string without HTML in it can be considered to be HTML still
158
158
  var _isHtml = function ( d ) {
159
- return !d || typeof d === 'string';
159
+ return _empty( d ) || typeof d === 'string';
160
160
  };
161
161
 
162
162
 
@@ -210,7 +210,9 @@
210
210
  // is essential here
211
211
  if ( prop2 !== undefined ) {
212
212
  for ( ; i<ien ; i++ ) {
213
- out.push( a[ order[i] ][ prop ][ prop2 ] );
213
+ if ( a[ order[i] ][ prop ] ) {
214
+ out.push( a[ order[i] ][ prop ][ prop2 ] );
215
+ }
214
216
  }
215
217
  }
216
218
  else {
@@ -245,6 +247,20 @@
245
247
  };
246
248
 
247
249
 
250
+ var _removeEmpty = function ( a )
251
+ {
252
+ var out = [];
253
+
254
+ for ( var i=0, ien=a.length ; i<ien ; i++ ) {
255
+ if ( a[i] ) { // careful - will remove all falsy values!
256
+ out.push( a[i] );
257
+ }
258
+ }
259
+
260
+ return out;
261
+ };
262
+
263
+
248
264
  var _stripHtml = function ( d ) {
249
265
  return d.replace( _re_html, '' );
250
266
  };
@@ -310,7 +326,6 @@
310
326
  newKey = key.replace( match[0], match[2].toLowerCase() );
311
327
  map[ newKey ] = key;
312
328
 
313
- //console.log( key, match );
314
329
  if ( match[1] === 'o' )
315
330
  {
316
331
  _fnHungarianMap( o[key] );
@@ -436,6 +451,18 @@
436
451
  _fnCompatMap( init, 'pagingType', 'sPaginationType' );
437
452
  _fnCompatMap( init, 'pageLength', 'iDisplayLength' );
438
453
  _fnCompatMap( init, 'searching', 'bFilter' );
454
+
455
+ // Column search objects are in an array, so it needs to be converted
456
+ // element by element
457
+ var searchCols = init.aoSearchCols;
458
+
459
+ if ( searchCols ) {
460
+ for ( var i=0, ien=searchCols.length ; i<ien ; i++ ) {
461
+ if ( searchCols[i] ) {
462
+ _fnCamelToHungarian( DataTable.models.oSearch, searchCols[i] );
463
+ }
464
+ }
465
+ }
439
466
  }
440
467
 
441
468
 
@@ -592,7 +619,7 @@
592
619
  oCol.sWidthOrig = th.attr('width') || null;
593
620
 
594
621
  // Style attribute
595
- var t = (th.attr('style') || '').match(/width:\s*(\d+[pxem%])/);
622
+ var t = (th.attr('style') || '').match(/width:\s*(\d+[pxem%]+)/);
596
623
  if ( t ) {
597
624
  oCol.sWidthOrig = t[1];
598
625
  }
@@ -650,16 +677,22 @@
650
677
  attrTest(mDataSrc.sort) || attrTest(mDataSrc.type) || attrTest(mDataSrc.filter)
651
678
  );
652
679
 
653
- oCol.fnGetData = function (oData, sSpecific) {
654
- var innerData = mData( oData, sSpecific );
680
+ oCol.fnGetData = function (rowData, type, meta) {
681
+ var innerData = mData( rowData, type, undefined, meta );
655
682
 
656
- if ( oCol.mRender && (sSpecific && sSpecific !== '') )
657
- {
658
- return mRender( innerData, sSpecific, oData );
659
- }
660
- return innerData;
683
+ return mRender && type ?
684
+ mRender( innerData, type, rowData, meta ) :
685
+ innerData;
686
+ };
687
+ oCol.fnSetData = function ( rowData, val, meta ) {
688
+ return _fnSetObjectDataFn( mDataSrc )( rowData, val, meta );
661
689
  };
662
- oCol.fnSetData = _fnSetObjectDataFn( mDataSrc );
690
+
691
+ // Indicate if DataTables should read DOM data as an object or array
692
+ // Used in _fnGetRowElements
693
+ if ( typeof mDataSrc !== 'number' ) {
694
+ oSettings._rowReadObject = true;
695
+ }
663
696
 
664
697
  /* Feature sorting overrides column specific when off */
665
698
  if ( !oSettings.oFeatures.bSort )
@@ -825,11 +858,18 @@
825
858
 
826
859
  detectedType = types[j]( cache[k], settings );
827
860
 
828
- // Doesn't match, so break early, since this type can't
829
- // apply to this column. Also, HTML is a special case since
830
- // it is so similar to `string`. Just a single match is
831
- // needed for a column to be html type
832
- if ( ! detectedType || detectedType === 'html' ) {
861
+ // If null, then this type can't apply to this column, so
862
+ // rather than testing all cells, break out. There is an
863
+ // exception for the last type which is `html`. We need to
864
+ // scan all rows since it is possible to mix string and HTML
865
+ // types
866
+ if ( ! detectedType && j !== types.length-1 ) {
867
+ break;
868
+ }
869
+
870
+ // Only a single match is needed for html type since it is
871
+ // bottom of the pile and very similar to string
872
+ if ( detectedType === 'html' ) {
833
873
  break;
834
874
  }
835
875
  }
@@ -970,8 +1010,8 @@
970
1010
  /* Add to the display array */
971
1011
  oSettings.aiDisplayMaster.push( iRow );
972
1012
 
973
- /* Create the DOM information */
974
- if ( !oSettings.oFeatures.bDeferRender )
1013
+ /* Create the DOM information, or register it if already present */
1014
+ if ( nTr || ! oSettings.oFeatures.bDeferRender )
975
1015
  {
976
1016
  _fnCreateTr( oSettings, iRow, nTr, anTds );
977
1017
  }
@@ -1035,64 +1075,70 @@
1035
1075
 
1036
1076
  /**
1037
1077
  * Get the data for a given cell from the internal cache, taking into account data mapping
1038
- * @param {object} oSettings dataTables settings object
1039
- * @param {int} iRow aoData row id
1040
- * @param {int} iCol Column index
1041
- * @param {string} sSpecific data get type ('display', 'type' 'filter' 'sort')
1078
+ * @param {object} settings dataTables settings object
1079
+ * @param {int} rowIdx aoData row id
1080
+ * @param {int} colIdx Column index
1081
+ * @param {string} type data get type ('display', 'type' 'filter' 'sort')
1042
1082
  * @returns {*} Cell data
1043
1083
  * @memberof DataTable#oApi
1044
1084
  */
1045
- function _fnGetCellData( oSettings, iRow, iCol, sSpecific )
1085
+ function _fnGetCellData( settings, rowIdx, colIdx, type )
1046
1086
  {
1047
- var oCol = oSettings.aoColumns[iCol];
1048
- var oData = oSettings.aoData[iRow]._aData;
1049
- var sData = oCol.fnGetData( oData, sSpecific );
1087
+ var draw = settings.iDraw;
1088
+ var col = settings.aoColumns[colIdx];
1089
+ var rowData = settings.aoData[rowIdx]._aData;
1090
+ var defaultContent = col.sDefaultContent;
1091
+ var cellData = col.fnGetData( rowData, type, {
1092
+ settings: settings,
1093
+ row: rowIdx,
1094
+ col: colIdx
1095
+ } );
1050
1096
 
1051
- if ( sData === undefined )
1052
- {
1053
- if ( oSettings.iDrawError != oSettings.iDraw && oCol.sDefaultContent === null )
1054
- {
1055
- _fnLog( oSettings, 0, "Requested unknown parameter "+
1056
- (typeof oCol.mData=='function' ? '{function}' : "'"+oCol.mData+"'")+
1057
- " for row "+iRow, 4 );
1058
- oSettings.iDrawError = oSettings.iDraw;
1097
+ if ( cellData === undefined ) {
1098
+ if ( settings.iDrawError != draw && defaultContent === null ) {
1099
+ _fnLog( settings, 0, "Requested unknown parameter "+
1100
+ (typeof col.mData=='function' ? '{function}' : "'"+col.mData+"'")+
1101
+ " for row "+rowIdx, 4 );
1102
+ settings.iDrawError = draw;
1059
1103
  }
1060
- return oCol.sDefaultContent;
1104
+ return defaultContent;
1061
1105
  }
1062
1106
 
1063
1107
  /* When the data source is null, we can use default column data */
1064
- if ( (sData === oData || sData === null) && oCol.sDefaultContent !== null )
1065
- {
1066
- sData = oCol.sDefaultContent;
1108
+ if ( (cellData === rowData || cellData === null) && defaultContent !== null ) {
1109
+ cellData = defaultContent;
1067
1110
  }
1068
- else if ( typeof sData === 'function' )
1069
- {
1070
- // If the data source is a function, then we run it and use the return
1071
- return sData();
1111
+ else if ( typeof cellData === 'function' ) {
1112
+ // If the data source is a function, then we run it and use the return,
1113
+ // executing in the scope of the data object (for instances)
1114
+ return cellData.call( rowData );
1072
1115
  }
1073
1116
 
1074
- if ( sData === null && sSpecific == 'display' )
1075
- {
1117
+ if ( cellData === null && type == 'display' ) {
1076
1118
  return '';
1077
1119
  }
1078
- return sData;
1120
+ return cellData;
1079
1121
  }
1080
1122
 
1081
1123
 
1082
1124
  /**
1083
1125
  * Set the value for a specific cell, into the internal data cache
1084
- * @param {object} oSettings dataTables settings object
1085
- * @param {int} iRow aoData row id
1086
- * @param {int} iCol Column index
1126
+ * @param {object} settings dataTables settings object
1127
+ * @param {int} rowIdx aoData row id
1128
+ * @param {int} colIdx Column index
1087
1129
  * @param {*} val Value to set
1088
1130
  * @memberof DataTable#oApi
1089
1131
  */
1090
- function _fnSetCellData( oSettings, iRow, iCol, val )
1132
+ function _fnSetCellData( settings, rowIdx, colIdx, val )
1091
1133
  {
1092
- var oCol = oSettings.aoColumns[iCol];
1093
- var oData = oSettings.aoData[iRow]._aData;
1094
-
1095
- oCol.fnSetData( oData, val );
1134
+ var col = settings.aoColumns[colIdx];
1135
+ var rowData = settings.aoData[rowIdx]._aData;
1136
+
1137
+ col.fnSetData( rowData, val, {
1138
+ settings: settings,
1139
+ row: rowIdx,
1140
+ col: colIdx
1141
+ } );
1096
1142
  }
1097
1143
 
1098
1144
 
@@ -1108,7 +1154,7 @@
1108
1154
  function _fnSplitObjNotation( str )
1109
1155
  {
1110
1156
  return $.map( str.match(/(\\.|[^\.])+/g), function ( s ) {
1111
- return s.replace('\\.', '.');
1157
+ return s.replace(/\\./g, '.');
1112
1158
  } );
1113
1159
  }
1114
1160
 
@@ -1132,24 +1178,24 @@
1132
1178
  }
1133
1179
  } );
1134
1180
 
1135
- return function (data, type, extra) {
1181
+ return function (data, type, row, meta) {
1136
1182
  var t = o[type] || o._;
1137
1183
  return t !== undefined ?
1138
- t(data, type, extra) :
1184
+ t(data, type, row, meta) :
1139
1185
  data;
1140
1186
  };
1141
1187
  }
1142
1188
  else if ( mSource === null )
1143
1189
  {
1144
1190
  /* Give an empty string for rendering / sorting etc */
1145
- return function (data, type) {
1191
+ return function (data) { // type, row and meta also passed, but not used
1146
1192
  return data;
1147
1193
  };
1148
1194
  }
1149
1195
  else if ( typeof mSource === 'function' )
1150
1196
  {
1151
- return function (data, type, extra) {
1152
- return mSource( data, type, extra );
1197
+ return function (data, type, row, meta) {
1198
+ return mSource( data, type, row, meta );
1153
1199
  };
1154
1200
  }
1155
1201
  else if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 ||
@@ -1222,14 +1268,14 @@
1222
1268
  return data;
1223
1269
  };
1224
1270
 
1225
- return function (data, type) {
1271
+ return function (data, type) { // row and meta also passed, but not used
1226
1272
  return fetchData( data, type, mSource );
1227
1273
  };
1228
1274
  }
1229
1275
  else
1230
1276
  {
1231
1277
  /* Array or flat object mapping */
1232
- return function (data, type) {
1278
+ return function (data, type) { // row and meta also passed, but not used
1233
1279
  return data[mSource];
1234
1280
  };
1235
1281
  }
@@ -1257,12 +1303,12 @@
1257
1303
  else if ( mSource === null )
1258
1304
  {
1259
1305
  /* Nothing to do when the data source is null */
1260
- return function (data, val) {};
1306
+ return function () {};
1261
1307
  }
1262
1308
  else if ( typeof mSource === 'function' )
1263
1309
  {
1264
- return function (data, val) {
1265
- mSource( data, 'set', val );
1310
+ return function (data, val, meta) {
1311
+ mSource( data, 'set', val, meta );
1266
1312
  };
1267
1313
  }
1268
1314
  else if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 ||
@@ -1332,14 +1378,14 @@
1332
1378
  }
1333
1379
  };
1334
1380
 
1335
- return function (data, val) {
1381
+ return function (data, val) { // meta is also passed in, but not used
1336
1382
  return setData( data, val, mSource );
1337
1383
  };
1338
1384
  }
1339
1385
  else
1340
1386
  {
1341
1387
  /* Array or flat object mapping */
1342
- return function (data, val) {
1388
+ return function (data, val) { // meta is also passed in, but not used
1343
1389
  data[mSource] = val;
1344
1390
  };
1345
1391
  }
@@ -1406,51 +1452,75 @@
1406
1452
  * the cached data is next requested. Also update from the data source object.
1407
1453
  *
1408
1454
  * @param {object} settings DataTables settings object
1409
- * @param {int} rowIdx Row index to invalidate
1455
+ * @param {int} rowIdx Row index to invalidate
1456
+ * @param {string} [src] Source to invalidate from: undefined, 'auto', 'dom'
1457
+ * or 'data'
1458
+ * @param {int} [colIdx] Column index to invalidate. If undefined the whole
1459
+ * row will be invalidated
1410
1460
  * @memberof DataTable#oApi
1411
1461
  *
1412
1462
  * @todo For the modularisation of v1.11 this will need to become a callback, so
1413
1463
  * the sort and filter methods can subscribe to it. That will required
1414
1464
  * initialisation options for sorting, which is why it is not already baked in
1415
1465
  */
1416
- function _fnInvalidateRow( settings, rowIdx, src, column )
1466
+ function _fnInvalidate( settings, rowIdx, src, colIdx )
1417
1467
  {
1418
1468
  var row = settings.aoData[ rowIdx ];
1419
1469
  var i, ien;
1470
+ var cellWrite = function ( cell, col ) {
1471
+ // This is very frustrating, but in IE if you just write directly
1472
+ // to innerHTML, and elements that are overwritten are GC'ed,
1473
+ // even if there is a reference to them elsewhere
1474
+ while ( cell.childNodes.length ) {
1475
+ cell.removeChild( cell.firstChild );
1476
+ }
1477
+
1478
+ cell.innerHTML = _fnGetCellData( settings, rowIdx, col, 'display' );
1479
+ };
1420
1480
 
1421
1481
  // Are we reading last data from DOM or the data object?
1422
1482
  if ( src === 'dom' || ((! src || src === 'auto') && row.src === 'dom') ) {
1423
1483
  // Read the data from the DOM
1424
- row._aData = _fnGetRowElements( settings, row ).data;
1484
+ row._aData = _fnGetRowElements(
1485
+ settings, row, colIdx, colIdx === undefined ? undefined : row._aData
1486
+ )
1487
+ .data;
1425
1488
  }
1426
1489
  else {
1427
1490
  // Reading from data object, update the DOM
1428
1491
  var cells = row.anCells;
1429
1492
 
1430
1493
  if ( cells ) {
1431
- for ( i=0, ien=cells.length ; i<ien ; i++ ) {
1432
- cells[i].innerHTML = _fnGetCellData( settings, rowIdx, i, 'display' );
1494
+ if ( colIdx !== undefined ) {
1495
+ cellWrite( cells[colIdx], colIdx );
1496
+ }
1497
+ else {
1498
+ for ( i=0, ien=cells.length ; i<ien ; i++ ) {
1499
+ cellWrite( cells[i], i );
1500
+ }
1433
1501
  }
1434
1502
  }
1435
1503
  }
1436
1504
 
1505
+ // For both row and cell invalidation, the cached data for sorting and
1506
+ // filtering is nulled out
1437
1507
  row._aSortData = null;
1438
1508
  row._aFilterData = null;
1439
1509
 
1440
1510
  // Invalidate the type for a specific column (if given) or all columns since
1441
1511
  // the data might have changed
1442
1512
  var cols = settings.aoColumns;
1443
- if ( column !== undefined ) {
1444
- cols[ column ].sType = null;
1513
+ if ( colIdx !== undefined ) {
1514
+ cols[ colIdx ].sType = null;
1445
1515
  }
1446
1516
  else {
1447
1517
  for ( i=0, ien=cols.length ; i<ien ; i++ ) {
1448
1518
  cols[i].sType = null;
1449
1519
  }
1450
- }
1451
1520
 
1452
- // Update DataTables special `DT_*` attributes for the row
1453
- _fnRowAttributes( row );
1521
+ // Update DataTables special `DT_*` attributes for the row
1522
+ _fnRowAttributes( row );
1523
+ }
1454
1524
  }
1455
1525
 
1456
1526
 
@@ -1461,62 +1531,81 @@
1461
1531
  * @param {object} settings DataTables settings object
1462
1532
  * @param {node|object} TR element from which to read data or existing row
1463
1533
  * object from which to re-read the data from the cells
1534
+ * @param {int} [colIdx] Optional column index
1535
+ * @param {array|object} [d] Data source object. If `colIdx` is given then this
1536
+ * parameter should also be given and will be used to write the data into.
1537
+ * Only the column in question will be written
1464
1538
  * @returns {object} Object with two parameters: `data` the data read, in
1465
1539
  * document order, and `cells` and array of nodes (they can be useful to the
1466
1540
  * caller, so rather than needing a second traversal to get them, just return
1467
1541
  * them from here).
1468
1542
  * @memberof DataTable#oApi
1469
1543
  */
1470
- function _fnGetRowElements( settings, row )
1544
+ function _fnGetRowElements( settings, row, colIdx, d )
1471
1545
  {
1472
1546
  var
1473
- d = [],
1474
1547
  tds = [],
1475
1548
  td = row.firstChild,
1476
1549
  name, col, o, i=0, contents,
1477
- columns = settings.aoColumns;
1550
+ columns = settings.aoColumns,
1551
+ objectRead = settings._rowReadObject;
1478
1552
 
1479
- var attr = function ( str, data, td ) {
1553
+ // Allow the data object to be passed in, or construct
1554
+ d = d || objectRead ? {} : [];
1555
+
1556
+ var attr = function ( str, td ) {
1480
1557
  if ( typeof str === 'string' ) {
1481
1558
  var idx = str.indexOf('@');
1482
1559
 
1483
1560
  if ( idx !== -1 ) {
1484
- var src = str.substring( idx+1 );
1485
- o[ '@'+src ] = td.getAttribute( src );
1561
+ var attr = str.substring( idx+1 );
1562
+ var setter = _fnSetObjectDataFn( str );
1563
+ setter( d, td.getAttribute( attr ) );
1486
1564
  }
1487
1565
  }
1488
1566
  };
1489
1567
 
1568
+ // Read data from a cell and store into the data object
1490
1569
  var cellProcess = function ( cell ) {
1491
- col = columns[i];
1492
- contents = $.trim(cell.innerHTML);
1570
+ if ( colIdx === undefined || colIdx === i ) {
1571
+ col = columns[i];
1572
+ contents = $.trim(cell.innerHTML);
1493
1573
 
1494
- if ( col && col._bAttrSrc ) {
1495
- o = {
1496
- display: contents
1497
- };
1498
-
1499
- attr( col.mData.sort, o, cell );
1500
- attr( col.mData.type, o, cell );
1501
- attr( col.mData.filter, o, cell );
1574
+ if ( col && col._bAttrSrc ) {
1575
+ var setter = _fnSetObjectDataFn( col.mData._ );
1576
+ setter( d, contents );
1502
1577
 
1503
- d.push( o );
1504
- }
1505
- else {
1506
- d.push( contents );
1578
+ attr( col.mData.sort, cell );
1579
+ attr( col.mData.type, cell );
1580
+ attr( col.mData.filter, cell );
1581
+ }
1582
+ else {
1583
+ // Depending on the `data` option for the columns the data can
1584
+ // be read to either an object or an array.
1585
+ if ( objectRead ) {
1586
+ if ( ! col._setter ) {
1587
+ // Cache the setter function
1588
+ col._setter = _fnSetObjectDataFn( col.mData );
1589
+ }
1590
+ col._setter( d, contents );
1591
+ }
1592
+ else {
1593
+ d[i] = contents;
1594
+ }
1595
+ }
1507
1596
  }
1508
1597
 
1509
- tds.push( cell );
1510
1598
  i++;
1511
1599
  };
1512
1600
 
1513
1601
  if ( td ) {
1514
- // `tr` element passed in
1602
+ // `tr` element was passed in
1515
1603
  while ( td ) {
1516
1604
  name = td.nodeName.toUpperCase();
1517
1605
 
1518
1606
  if ( name == "TD" || name == "TH" ) {
1519
1607
  cellProcess( td );
1608
+ tds.push( td );
1520
1609
  }
1521
1610
 
1522
1611
  td = td.nextSibling;
@@ -1603,7 +1692,7 @@
1603
1692
  if ( oCol.fnCreatedCell )
1604
1693
  {
1605
1694
  oCol.fnCreatedCell.call( oSettings.oInstance,
1606
- nTd, _fnGetCellData( oSettings, iRow, i, 'display' ), rowData, iRow, i
1695
+ nTd, _fnGetCellData( oSettings, iRow, i ), rowData, iRow, i
1607
1696
  );
1608
1697
  }
1609
1698
  }
@@ -1922,7 +2011,9 @@
1922
2011
  }
1923
2012
  }
1924
2013
 
1925
- /* Row callback functions - might want to manipulate the row */
2014
+ // Row callback functions - might want to manipulate the row
2015
+ // iRowCount and j are not currently documented. Are they at all
2016
+ // useful?
1926
2017
  _fnCallbackFire( oSettings, 'aoRowCallback', null,
1927
2018
  [nRow, aoData._aData, iRowCount, j] );
1928
2019
 
@@ -2003,7 +2094,13 @@
2003
2094
  settings._iDisplayStart = 0;
2004
2095
  }
2005
2096
 
2097
+ // Let any modules know about the draw hold position state (used by
2098
+ // scrolling internally)
2099
+ settings._drawHold = holdPosition;
2100
+
2006
2101
  _fnDraw( settings );
2102
+
2103
+ settings._drawHold = false;
2007
2104
  }
2008
2105
 
2009
2106
 
@@ -2405,22 +2502,23 @@
2405
2502
 
2406
2503
  /**
2407
2504
  * Update the table using an Ajax call
2408
- * @param {object} oSettings dataTables settings object
2505
+ * @param {object} settings dataTables settings object
2409
2506
  * @returns {boolean} Block the table drawing or not
2410
2507
  * @memberof DataTable#oApi
2411
2508
  */
2412
- function _fnAjaxUpdate( oSettings )
2509
+ function _fnAjaxUpdate( settings )
2413
2510
  {
2414
- if ( oSettings.bAjaxDataGet )
2415
- {
2416
- oSettings.iDraw++;
2417
- _fnProcessingDisplay( oSettings, true );
2418
- var iColumns = oSettings.aoColumns.length;
2419
- var aoData = _fnAjaxParameters( oSettings );
2511
+ if ( settings.bAjaxDataGet ) {
2512
+ settings.iDraw++;
2513
+ _fnProcessingDisplay( settings, true );
2420
2514
 
2421
- _fnBuildAjax( oSettings, aoData, function(json) {
2422
- _fnAjaxUpdateDraw( oSettings, json );
2423
- }, oSettings );
2515
+ _fnBuildAjax(
2516
+ settings,
2517
+ _fnAjaxParameters( settings ),
2518
+ function(json) {
2519
+ _fnAjaxUpdateDraw( settings, json );
2520
+ }
2521
+ );
2424
2522
 
2425
2523
  return false;
2426
2524
  }
@@ -2554,11 +2652,10 @@
2554
2652
  var compat = function ( old, modern ) {
2555
2653
  return json[old] !== undefined ? json[old] : json[modern];
2556
2654
  };
2557
- var data = _fnAjaxDataSrc( settings, json );
2558
2655
 
2559
- var draw = compat( 'sEcho', 'draw' );
2560
- var recordsTotal = compat( 'totaliTotalRecords', 'recordsTotal' );
2561
- var rocordsFiltered = compat( 'iTotalDisplayRecords', 'recordsFiltered' );
2656
+ var draw = compat( 'sEcho', 'draw' );
2657
+ var recordsTotal = compat( 'iTotalRecords', 'recordsTotal' );
2658
+ var recordsFiltered = compat( 'iTotalDisplayRecords', 'recordsFiltered' );
2562
2659
 
2563
2660
  if ( draw ) {
2564
2661
  // Protect against out of sequence returns
@@ -2570,8 +2667,9 @@
2570
2667
 
2571
2668
  _fnClearTable( settings );
2572
2669
  settings._iRecordsTotal = parseInt(recordsTotal, 10);
2573
- settings._iRecordsDisplay = parseInt(rocordsFiltered, 10);
2670
+ settings._iRecordsDisplay = parseInt(recordsFiltered, 10);
2574
2671
 
2672
+ var data = _fnAjaxDataSrc( settings, json );
2575
2673
  for ( var i=0, ien=data.length ; i<ien ; i++ ) {
2576
2674
  _fnAddData( settings, data[i] );
2577
2675
  }
@@ -2625,11 +2723,12 @@
2625
2723
  {
2626
2724
  var classes = settings.oClasses;
2627
2725
  var tableId = settings.sTableId;
2726
+ var language = settings.oLanguage;
2628
2727
  var previousSearch = settings.oPreviousSearch;
2629
2728
  var features = settings.aanFeatures;
2630
2729
  var input = '<input type="search" class="'+classes.sFilterInput+'"/>';
2631
2730
 
2632
- var str = settings.oLanguage.sSearch;
2731
+ var str = language.sSearch;
2633
2732
  str = str.match(/_INPUT_/) ?
2634
2733
  str.replace('_INPUT_', input) :
2635
2734
  str+input;
@@ -2659,12 +2758,20 @@
2659
2758
  _fnDraw( settings );
2660
2759
  }
2661
2760
  };
2761
+
2762
+ var searchDelay = settings.searchDelay !== null ?
2763
+ settings.searchDelay :
2764
+ _fnDataSource( settings ) === 'ssp' ?
2765
+ 400 :
2766
+ 0;
2767
+
2662
2768
  var jqFilter = $('input', filter)
2663
- .val( previousSearch.sSearch.replace('"','&quot;') )
2769
+ .val( previousSearch.sSearch )
2770
+ .attr( 'placeholder', language.sSearchPlaceholder )
2664
2771
  .bind(
2665
2772
  'keyup.DT search.DT input.DT paste.DT cut.DT',
2666
- _fnDataSource( settings ) === 'ssp' ?
2667
- _fnThrottle( searchFn, 400 ):
2773
+ searchDelay ?
2774
+ _fnThrottle( searchFn, searchDelay ) :
2668
2775
  searchFn
2669
2776
  )
2670
2777
  .bind( 'keypress.DT', function(e) {
@@ -2676,15 +2783,17 @@
2676
2783
  .attr('aria-controls', tableId);
2677
2784
 
2678
2785
  // Update the input elements whenever the table is filtered
2679
- $(settings.nTable).on( 'filter.DT', function () {
2680
- // IE9 throws an 'unknown error' if document.activeElement is used
2681
- // inside an iframe or frame...
2682
- try {
2683
- if ( jqFilter[0] !== document.activeElement ) {
2684
- jqFilter.val( previousSearch.sSearch );
2786
+ $(settings.nTable).on( 'search.dt.DT', function ( ev, s ) {
2787
+ if ( settings === s ) {
2788
+ // IE9 throws an 'unknown error' if document.activeElement is used
2789
+ // inside an iframe or frame...
2790
+ try {
2791
+ if ( jqFilter[0] !== document.activeElement ) {
2792
+ jqFilter.val( previousSearch.sSearch );
2793
+ }
2685
2794
  }
2795
+ catch ( e ) {}
2686
2796
  }
2687
- catch ( e ) {}
2688
2797
  } );
2689
2798
 
2690
2799
  return filter[0];
@@ -2757,15 +2866,23 @@
2757
2866
  var displayRows = settings.aiDisplay;
2758
2867
  var row, rowIdx;
2759
2868
 
2760
- for ( var i=0, iLen=filters.length ; i<iLen ; i++ ) {
2761
- for ( var j=displayRows.length-1 ; j>=0 ; j-- ) {
2869
+ for ( var i=0, ien=filters.length ; i<ien ; i++ ) {
2870
+ var rows = [];
2871
+
2872
+ // Loop over each row and see if it should be included
2873
+ for ( var j=0, jen=displayRows.length ; j<jen ; j++ ) {
2762
2874
  rowIdx = displayRows[ j ];
2763
2875
  row = settings.aoData[ rowIdx ];
2764
2876
 
2765
- if ( ! filters[i]( settings, row._aFilterData, rowIdx, row._aData ) ) {
2766
- displayRows.splice( j, 1 );
2877
+ if ( filters[i]( settings, row._aFilterData, rowIdx, row._aData, j ) ) {
2878
+ rows.push( rowIdx );
2767
2879
  }
2768
2880
  }
2881
+
2882
+ // So the array reference doesn't break set the results into the
2883
+ // existing array
2884
+ displayRows.length = 0;
2885
+ displayRows.push.apply( displayRows, rows );
2769
2886
  }
2770
2887
  }
2771
2888
 
@@ -2877,9 +2994,12 @@
2877
2994
  * ^(?=.*?\bone\b)(?=.*?\btwo three\b)(?=.*?\bfour\b).*$
2878
2995
  */
2879
2996
  var a = $.map( search.match( /"[^"]+"|[^ ]+/g ) || '', function ( word ) {
2880
- return word.charAt(0) === '"' ?
2881
- word.match( /^"(.*)"$/ )[1] :
2882
- word;
2997
+ if ( word.charAt(0) === '"' ) {
2998
+ var m = word.match( /^"(.*)"$/ );
2999
+ word = m ? m[1] : word;
3000
+ }
3001
+
3002
+ return word.replace('"', '');
2883
3003
  } );
2884
3004
 
2885
3005
  search = '^(?=.*?'+a.join( ')(?=.*?' )+').*$';
@@ -2890,7 +3010,7 @@
2890
3010
 
2891
3011
 
2892
3012
  /**
2893
- * scape a string such that it can be used in a regular expression
3013
+ * Escape a string such that it can be used in a regular expression
2894
3014
  * @param {string} sVal string to escape
2895
3015
  * @returns {string} escaped string
2896
3016
  * @memberof DataTable#oApi
@@ -2926,11 +3046,19 @@
2926
3046
  if ( column.bSearchable ) {
2927
3047
  cellData = _fnGetCellData( settings, i, j, 'filter' );
2928
3048
 
2929
- cellData = fomatters[ column.sType ] ?
2930
- fomatters[ column.sType ]( cellData ) :
2931
- cellData !== null ?
2932
- cellData :
2933
- '';
3049
+ if ( fomatters[ column.sType ] ) {
3050
+ cellData = fomatters[ column.sType ]( cellData );
3051
+ }
3052
+
3053
+ // Search in DataTables 1.10 is string based. In 1.11 this
3054
+ // should be altered to also allow strict type checking.
3055
+ if ( cellData === null ) {
3056
+ cellData = '';
3057
+ }
3058
+
3059
+ if ( typeof cellData !== 'string' && cellData.toString ) {
3060
+ cellData = cellData.toString();
3061
+ }
2934
3062
  }
2935
3063
  else {
2936
3064
  cellData = '';
@@ -2963,6 +3091,43 @@
2963
3091
  return wasInvalidated;
2964
3092
  }
2965
3093
 
3094
+
3095
+ /**
3096
+ * Convert from the internal Hungarian notation to camelCase for external
3097
+ * interaction
3098
+ * @param {object} obj Object to convert
3099
+ * @returns {object} Inverted object
3100
+ * @memberof DataTable#oApi
3101
+ */
3102
+ function _fnSearchToCamel ( obj )
3103
+ {
3104
+ return {
3105
+ search: obj.sSearch,
3106
+ smart: obj.bSmart,
3107
+ regex: obj.bRegex,
3108
+ caseInsensitive: obj.bCaseInsensitive
3109
+ };
3110
+ }
3111
+
3112
+
3113
+
3114
+ /**
3115
+ * Convert from camelCase notation to the internal Hungarian. We could use the
3116
+ * Hungarian convert function here, but this is cleaner
3117
+ * @param {object} obj Object to convert
3118
+ * @returns {object} Inverted object
3119
+ * @memberof DataTable#oApi
3120
+ */
3121
+ function _fnSearchToHung ( obj )
3122
+ {
3123
+ return {
3124
+ sSearch: obj.search,
3125
+ bSmart: obj.smart,
3126
+ bRegex: obj.regex,
3127
+ bCaseInsensitive: obj.caseInsensitive
3128
+ };
3129
+ }
3130
+
2966
3131
  /**
2967
3132
  * Generate the node required for the info display
2968
3133
  * @param {object} oSettings dataTables settings object
@@ -3206,13 +3371,12 @@
3206
3371
  div[0].id = tableId+'_length';
3207
3372
  }
3208
3373
 
3209
- var a = settings.oLanguage.sLengthMenu.split(/(_MENU_)/);
3210
- div.children().append( a.length > 1 ?
3211
- [ a[0], select, a[2] ] :
3212
- a[0]
3374
+ div.children().append(
3375
+ settings.oLanguage.sLengthMenu.replace( '_MENU_', select[0].outerHTML )
3213
3376
  );
3214
3377
 
3215
- // Can't use `select` variable, as user might provide their own select menu
3378
+ // Can't use `select` variable as user might provide their own and the
3379
+ // reference is broken by the use of outerHTML
3216
3380
  $('select', div)
3217
3381
  .val( settings._iDisplayLength )
3218
3382
  .bind( 'change.DT', function(e) {
@@ -3222,7 +3386,9 @@
3222
3386
 
3223
3387
  // Update node value whenever anything changes the table's length
3224
3388
  $(settings.nTable).bind( 'length.dt.DT', function (e, s, len) {
3225
- $('select', div).val( len );
3389
+ if ( settings === s ) {
3390
+ $('select', div).val( len );
3391
+ }
3226
3392
  } );
3227
3393
 
3228
3394
  return div[0];
@@ -3484,12 +3650,12 @@
3484
3650
  headerClone
3485
3651
  .removeAttr('id')
3486
3652
  .css( 'margin-left', 0 )
3653
+ .append( captionSide === 'top' ? caption : null )
3487
3654
  .append(
3488
3655
  table.children('thead')
3489
3656
  )
3490
3657
  )
3491
3658
  )
3492
- .append( captionSide === 'top' ? caption : null )
3493
3659
  )
3494
3660
  .append(
3495
3661
  $(_div, { 'class': classes.sScrollBody } )
@@ -3515,12 +3681,12 @@
3515
3681
  footerClone
3516
3682
  .removeAttr('id')
3517
3683
  .css( 'margin-left', 0 )
3684
+ .append( captionSide === 'bottom' ? caption : null )
3518
3685
  .append(
3519
3686
  table.children('tfoot')
3520
3687
  )
3521
3688
  )
3522
3689
  )
3523
- .append( captionSide === 'bottom' ? caption : null )
3524
3690
  );
3525
3691
  }
3526
3692
 
@@ -3844,8 +4010,9 @@
3844
4010
  /* Adjust the position of the header in case we loose the y-scrollbar */
3845
4011
  divBody.scroll();
3846
4012
 
3847
- /* If sorting or filtering has occurred, jump the scrolling back to the top */
3848
- if ( settings.bSorted || settings.bFiltered ) {
4013
+ // If sorting or filtering has occurred, jump the scrolling back to the top
4014
+ // only if we aren't holding the position
4015
+ if ( (settings.bSorted || settings.bFiltered) && ! settings._drawHold ) {
3849
4016
  divBodyEl.scrollTop = 0;
3850
4017
  }
3851
4018
  }
@@ -3945,7 +4112,8 @@
3945
4112
  // Otherwise construct a single row table with the widest node in the
3946
4113
  // data, assign any user defined widths, then insert it into the DOM and
3947
4114
  // allow the browser to do all the hard work of calculating table widths
3948
- var tmpTable = $( table.cloneNode( false ) )
4115
+ var tmpTable = $(table).clone() // don't use cloneNode - IE8 will remove events on the main table
4116
+ .empty()
3949
4117
  .css( 'visibility', 'hidden' )
3950
4118
  .removeAttr( 'id' )
3951
4119
  .append( $(oSettings.nTHead).clone( false ) )
@@ -4073,7 +4241,7 @@
4073
4241
  */
4074
4242
  function _fnThrottle( fn, freq ) {
4075
4243
  var
4076
- frequency = freq || 200,
4244
+ frequency = freq !== undefined ? freq : 200,
4077
4245
  last,
4078
4246
  timer;
4079
4247
 
@@ -4314,11 +4482,15 @@
4314
4482
  iCol = aDataSort[k];
4315
4483
  sType = aoColumns[ iCol ].sType || 'string';
4316
4484
 
4485
+ if ( nestedSort[i]._idx === undefined ) {
4486
+ nestedSort[i]._idx = $.inArray( nestedSort[i][1], aoColumns[iCol].asSorting );
4487
+ }
4488
+
4317
4489
  aSort.push( {
4318
4490
  src: srcCol,
4319
4491
  col: iCol,
4320
4492
  dir: nestedSort[i][1],
4321
- index: nestedSort[i][2],
4493
+ index: nestedSort[i]._idx,
4322
4494
  type: sType,
4323
4495
  formatter: DataTable.ext.type.order[ sType+"-pre" ]
4324
4496
  } );
@@ -4521,15 +4693,24 @@
4521
4693
  var sorting = settings.aaSorting;
4522
4694
  var asSorting = col.asSorting;
4523
4695
  var nextSortIdx;
4524
- var next = function ( a ) {
4696
+ var next = function ( a, overflow ) {
4525
4697
  var idx = a._idx;
4526
4698
  if ( idx === undefined ) {
4527
4699
  idx = $.inArray( a[1], asSorting );
4528
4700
  }
4529
4701
 
4530
- return idx+1 >= asSorting.length ? 0 : idx+1;
4702
+ return idx+1 < asSorting.length ?
4703
+ idx+1 :
4704
+ overflow ?
4705
+ null :
4706
+ 0;
4531
4707
  };
4532
4708
 
4709
+ // Convert to 2D array if needed
4710
+ if ( typeof sorting[0] === 'number' ) {
4711
+ sorting = settings.aaSorting = [ sorting ];
4712
+ }
4713
+
4533
4714
  // If appending the sort then we are multi-column sorting
4534
4715
  if ( append && settings.oFeatures.bSortMulti ) {
4535
4716
  // Are we already doing some kind of sort on this column?
@@ -4537,10 +4718,15 @@
4537
4718
 
4538
4719
  if ( sortIdx !== -1 ) {
4539
4720
  // Yes, modify the sort
4540
- nextSortIdx = next( sorting[sortIdx] );
4721
+ nextSortIdx = next( sorting[sortIdx], true );
4541
4722
 
4542
- sorting[sortIdx][1] = asSorting[ nextSortIdx ];
4543
- sorting[sortIdx]._idx = nextSortIdx;
4723
+ if ( nextSortIdx === null ) {
4724
+ sorting.splice( sortIdx, 1 );
4725
+ }
4726
+ else {
4727
+ sorting[sortIdx][1] = asSorting[ nextSortIdx ];
4728
+ sorting[sortIdx]._idx = nextSortIdx;
4729
+ }
4544
4730
  }
4545
4731
  else {
4546
4732
  // No sort on this column yet
@@ -4695,28 +4881,32 @@
4695
4881
  * @param {object} oSettings dataTables settings object
4696
4882
  * @memberof DataTable#oApi
4697
4883
  */
4698
- function _fnSaveState ( oSettings )
4884
+ function _fnSaveState ( settings )
4699
4885
  {
4700
- if ( !oSettings.oFeatures.bStateSave || oSettings.bDestroying )
4886
+ if ( !settings.oFeatures.bStateSave || settings.bDestroying )
4701
4887
  {
4702
4888
  return;
4703
4889
  }
4704
4890
 
4705
4891
  /* Store the interesting variables */
4706
- var i, iLen;
4707
- var oState = {
4708
- "iCreate": +new Date(),
4709
- "iStart": oSettings._iDisplayStart,
4710
- "iLength": oSettings._iDisplayLength,
4711
- "aaSorting": $.extend( true, [], oSettings.aaSorting ),
4712
- "oSearch": $.extend( true, {}, oSettings.oPreviousSearch ),
4713
- "aoSearchCols": $.extend( true, [], oSettings.aoPreSearchCols ),
4714
- "abVisCols": _pluck( oSettings.aoColumns, 'bVisible' )
4892
+ var state = {
4893
+ time: +new Date(),
4894
+ start: settings._iDisplayStart,
4895
+ length: settings._iDisplayLength,
4896
+ order: $.extend( true, [], settings.aaSorting ),
4897
+ search: _fnSearchToCamel( settings.oPreviousSearch ),
4898
+ columns: $.map( settings.aoColumns, function ( col, i ) {
4899
+ return {
4900
+ visible: col.bVisible,
4901
+ search: _fnSearchToCamel( settings.aoPreSearchCols[i] )
4902
+ };
4903
+ } )
4715
4904
  };
4716
4905
 
4717
- _fnCallbackFire( oSettings, "aoStateSaveParams", 'stateSaveParams', [oSettings, oState] );
4906
+ _fnCallbackFire( settings, "aoStateSaveParams", 'stateSaveParams', [settings, state] );
4718
4907
 
4719
- oSettings.fnStateSaveCallback.call( oSettings.oInstance, oSettings, oState );
4908
+ settings.oSavedState = state;
4909
+ settings.fnStateSaveCallback.call( settings.oInstance, settings, state );
4720
4910
  }
4721
4911
 
4722
4912
 
@@ -4726,63 +4916,72 @@
4726
4916
  * @param {object} oInit DataTables init object so we can override settings
4727
4917
  * @memberof DataTable#oApi
4728
4918
  */
4729
- function _fnLoadState ( oSettings, oInit )
4919
+ function _fnLoadState ( settings, oInit )
4730
4920
  {
4731
4921
  var i, ien;
4732
- var columns = oSettings.aoColumns;
4922
+ var columns = settings.aoColumns;
4733
4923
 
4734
- if ( ! oSettings.oFeatures.bStateSave ) {
4924
+ if ( ! settings.oFeatures.bStateSave ) {
4735
4925
  return;
4736
4926
  }
4737
4927
 
4738
- var oData = oSettings.fnStateLoadCallback.call( oSettings.oInstance, oSettings );
4739
- if ( !oData ) {
4928
+ var state = settings.fnStateLoadCallback.call( settings.oInstance, settings );
4929
+ if ( ! state || ! state.time ) {
4740
4930
  return;
4741
4931
  }
4742
4932
 
4743
4933
  /* Allow custom and plug-in manipulation functions to alter the saved data set and
4744
4934
  * cancelling of loading by returning false
4745
4935
  */
4746
- var abStateLoad = _fnCallbackFire( oSettings, 'aoStateLoadParams', 'stateLoadParams', [oSettings, oData] );
4936
+ var abStateLoad = _fnCallbackFire( settings, 'aoStateLoadParams', 'stateLoadParams', [settings, state] );
4747
4937
  if ( $.inArray( false, abStateLoad ) !== -1 ) {
4748
4938
  return;
4749
4939
  }
4750
4940
 
4751
4941
  /* Reject old data */
4752
- var duration = oSettings.iStateDuration;
4753
- if ( duration > 0 && oData.iCreate < +new Date() - (duration*1000) ) {
4942
+ var duration = settings.iStateDuration;
4943
+ if ( duration > 0 && state.time < +new Date() - (duration*1000) ) {
4754
4944
  return;
4755
4945
  }
4756
4946
 
4757
4947
  // Number of columns have changed - all bets are off, no restore of settings
4758
- if ( columns.length !== oData.aoSearchCols.length ) {
4948
+ if ( columns.length !== state.columns.length ) {
4759
4949
  return;
4760
4950
  }
4761
4951
 
4762
- /* Store the saved state so it might be accessed at any time */
4763
- oSettings.oLoadedState = $.extend( true, {}, oData );
4952
+ // Store the saved state so it might be accessed at any time
4953
+ settings.oLoadedState = $.extend( true, {}, state );
4954
+
4955
+ // Restore key features - todo - for 1.11 this needs to be done by
4956
+ // subscribed events
4957
+ settings._iDisplayStart = state.start;
4958
+ settings.iInitDisplayStart = state.start;
4959
+ settings._iDisplayLength = state.length;
4960
+ settings.aaSorting = [];
4764
4961
 
4765
- /* Restore key features */
4766
- oSettings._iDisplayStart = oData.iStart;
4767
- oSettings.iInitDisplayStart = oData.iStart;
4768
- oSettings._iDisplayLength = oData.iLength;
4769
- oSettings.aaSorting = $.map( oData.aaSorting, function ( col, i ) {
4770
- return col[0] >= columns.length ?
4962
+ // Order
4963
+ $.each( state.order, function ( i, col ) {
4964
+ settings.aaSorting.push( col[0] >= columns.length ?
4771
4965
  [ 0, col[1] ] :
4772
- col;
4966
+ col
4967
+ );
4773
4968
  } );
4774
4969
 
4775
- /* Search filtering */
4776
- $.extend( oSettings.oPreviousSearch, oData.oSearch );
4777
- $.extend( true, oSettings.aoPreSearchCols, oData.aoSearchCols );
4970
+ // Search
4971
+ $.extend( settings.oPreviousSearch, _fnSearchToHung( state.search ) );
4972
+
4973
+ // Columns
4974
+ for ( i=0, ien=state.columns.length ; i<ien ; i++ ) {
4975
+ var col = state.columns[i];
4778
4976
 
4779
- /* Column visibility state */
4780
- var visColumns = oData.abVisCols;
4781
- for ( i=0, ien=visColumns.length ; i<ien ; i++ ) {
4782
- columns[i].bVisible = visColumns[i];
4977
+ // Visibility
4978
+ columns[i].bVisible = col.visible;
4979
+
4980
+ // Search
4981
+ $.extend( settings.aoPreSearchCols[i], _fnSearchToHung( col.search ) );
4783
4982
  }
4784
4983
 
4785
- _fnCallbackFire( oSettings, 'aoStateLoaded', 'stateLoaded', [oSettings, oData] );
4984
+ _fnCallbackFire( settings, 'aoStateLoaded', 'stateLoaded', [settings, state] );
4786
4985
  }
4787
4986
 
4788
4987
 
@@ -4980,7 +5179,7 @@
4980
5179
  * trigger
4981
5180
  * @memberof DataTable#oApi
4982
5181
  */
4983
- function _fnCallbackFire( settings, callbackArr, event, args )
5182
+ function _fnCallbackFire( settings, callbackArr, e, args )
4984
5183
  {
4985
5184
  var ret = [];
4986
5185
 
@@ -4990,8 +5189,8 @@
4990
5189
  } );
4991
5190
  }
4992
5191
 
4993
- if ( event !== null ) {
4994
- $(settings.nTable).trigger( event+'.dt', args );
5192
+ if ( e !== null ) {
5193
+ $(settings.nTable).trigger( e+'.dt', args );
4995
5194
  }
4996
5195
 
4997
5196
  return ret;
@@ -5006,11 +5205,14 @@
5006
5205
  len = settings._iDisplayLength;
5007
5206
 
5008
5207
  /* If we have space to show extra rows (backing up from the end point - then do so */
5009
- if ( end === settings.fnRecordsDisplay() )
5208
+ if ( start >= end )
5010
5209
  {
5011
5210
  start = end - len;
5012
5211
  }
5013
5212
 
5213
+ // Keep the start record on the current page
5214
+ start -= (start % len);
5215
+
5014
5216
  if ( len === -1 || start < 0 )
5015
5217
  {
5016
5218
  start = 0;
@@ -5982,6 +6184,7 @@
5982
6184
  "fnStateLoadCallback",
5983
6185
  "fnStateSaveCallback",
5984
6186
  "renderer",
6187
+ "searchDelay",
5985
6188
  [ "iCookieDuration", "iStateDuration" ], // backwards compat
5986
6189
  [ "oSearch", "oPreviousSearch" ],
5987
6190
  [ "aoSearchCols", "aoPreSearchCols" ],
@@ -6063,26 +6266,31 @@
6063
6266
  }
6064
6267
 
6065
6268
  /* Language definitions */
6066
- if ( oInit.oLanguage.sUrl !== "" )
6269
+ var oLanguage = oSettings.oLanguage;
6270
+ $.extend( true, oLanguage, oInit.oLanguage );
6271
+
6272
+ if ( oLanguage.sUrl !== "" )
6067
6273
  {
6068
6274
  /* Get the language definitions from a file - because this Ajax call makes the language
6069
6275
  * get async to the remainder of this function we use bInitHandedOff to indicate that
6070
6276
  * _fnInitialise will be fired by the returned Ajax handler, rather than the constructor
6071
6277
  */
6072
- oSettings.oLanguage.sUrl = oInit.oLanguage.sUrl;
6073
- $.getJSON( oSettings.oLanguage.sUrl, null, function( json ) {
6074
- _fnLanguageCompat( json );
6075
- _fnCamelToHungarian( defaults.oLanguage, json );
6076
- $.extend( true, oSettings.oLanguage, oInit.oLanguage, json );
6077
- _fnInitialise( oSettings );
6278
+ $.ajax( {
6279
+ dataType: 'json',
6280
+ url: oLanguage.sUrl,
6281
+ success: function ( json ) {
6282
+ _fnLanguageCompat( json );
6283
+ _fnCamelToHungarian( defaults.oLanguage, json );
6284
+ $.extend( true, oLanguage, json );
6285
+ _fnInitialise( oSettings );
6286
+ },
6287
+ error: function () {
6288
+ // Error occurred loading language file, continue on as best we can
6289
+ _fnInitialise( oSettings );
6290
+ }
6078
6291
  } );
6079
6292
  bInitHandedOff = true;
6080
6293
  }
6081
- else
6082
- {
6083
- $.extend( true, oSettings.oLanguage, oInit.oLanguage );
6084
- }
6085
-
6086
6294
 
6087
6295
  /*
6088
6296
  * Stripes
@@ -6471,7 +6679,7 @@
6471
6679
  * // Initialisation as a constructor
6472
6680
  * var api = new $.fn.DataTable.Api( 'table.dataTable' );
6473
6681
  */
6474
- DataTable.Api = _Api = function ( context, data )
6682
+ _Api = function ( context, data )
6475
6683
  {
6476
6684
  if ( ! this instanceof _Api ) {
6477
6685
  throw 'DT API must be constructed as a new object';
@@ -6514,6 +6722,7 @@
6514
6722
  _Api.extend( this, this, __apiStruct );
6515
6723
  };
6516
6724
 
6725
+ DataTable.Api = _Api;
6517
6726
 
6518
6727
  _Api.prototype = /** @lends DataTables.Api */{
6519
6728
  /**
@@ -6536,16 +6745,8 @@
6536
6745
 
6537
6746
  each: function ( fn )
6538
6747
  {
6539
- if ( __arrayProto.forEach ) {
6540
- // Where possible, use the built-in forEach
6541
- __arrayProto.forEach.call( this, fn, this );
6542
- }
6543
- else {
6544
- // Compatibility for browsers without EMCA-252-5 (JS 1.6)
6545
- for ( var i=0, ien=this.length ; i<ien; i++ ) {
6546
- // In strict mode the execution scope is the passed value
6547
- fn.call( this, this[i], i, this );
6548
- }
6748
+ for ( var i=0, ien=this.length ; i<ien; i++ ) {
6749
+ fn.call( this, this[i], i, this );
6549
6750
  }
6550
6751
 
6551
6752
  return this;
@@ -6602,8 +6803,8 @@
6602
6803
  return -1;
6603
6804
  },
6604
6805
 
6605
- // Internal only at the moment - relax?
6606
- iterator: function ( flatten, type, fn ) {
6806
+ // Note that `alwaysNew` is internal - use iteratorNew externally
6807
+ iterator: function ( flatten, type, fn, alwaysNew ) {
6607
6808
  var
6608
6809
  a = [], ret,
6609
6810
  i, ien, j, jen,
@@ -6613,14 +6814,17 @@
6613
6814
 
6614
6815
  // Argument shifting
6615
6816
  if ( typeof flatten === 'string' ) {
6817
+ alwaysNew = fn;
6616
6818
  fn = type;
6617
6819
  type = flatten;
6618
6820
  flatten = false;
6619
6821
  }
6620
6822
 
6621
6823
  for ( i=0, ien=context.length ; i<ien ; i++ ) {
6824
+ var apiInst = new _Api( context[i] );
6825
+
6622
6826
  if ( type === 'table' ) {
6623
- ret = fn( context[i], i );
6827
+ ret = fn.call( apiInst, context[i], i );
6624
6828
 
6625
6829
  if ( ret !== undefined ) {
6626
6830
  a.push( ret );
@@ -6628,7 +6832,7 @@
6628
6832
  }
6629
6833
  else if ( type === 'columns' || type === 'rows' ) {
6630
6834
  // this has same length as context - one entry for each table
6631
- ret = fn( context[i], this[i], i );
6835
+ ret = fn.call( apiInst, context[i], this[i], i );
6632
6836
 
6633
6837
  if ( ret !== undefined ) {
6634
6838
  a.push( ret );
@@ -6647,10 +6851,10 @@
6647
6851
  item = items[j];
6648
6852
 
6649
6853
  if ( type === 'cell' ) {
6650
- ret = fn( context[i], item.row, item.column, i, j );
6854
+ ret = fn.call( apiInst, context[i], item.row, item.column, i, j );
6651
6855
  }
6652
6856
  else {
6653
- ret = fn( context[i], item, i, j, rows );
6857
+ ret = fn.call( apiInst, context[i], item, i, j, rows );
6654
6858
  }
6655
6859
 
6656
6860
  if ( ret !== undefined ) {
@@ -6660,7 +6864,7 @@
6660
6864
  }
6661
6865
  }
6662
6866
 
6663
- if ( a.length ) {
6867
+ if ( a.length || alwaysNew ) {
6664
6868
  var api = new _Api( context, flatten ? a.concat.apply( [], a ) : a );
6665
6869
  var apiSelector = api.selector;
6666
6870
  apiSelector.rows = selector.rows;
@@ -6781,7 +6985,7 @@
6781
6985
  i, ien,
6782
6986
  j, jen,
6783
6987
  struct, inner,
6784
- methodScoping = function ( fn, struc ) {
6988
+ methodScoping = function ( scope, fn, struc ) {
6785
6989
  return function () {
6786
6990
  var ret = fn.apply( scope, arguments );
6787
6991
 
@@ -6796,7 +7000,7 @@
6796
7000
 
6797
7001
  // Value
6798
7002
  obj[ struct.name ] = typeof struct.val === 'function' ?
6799
- methodScoping( struct.val, struct ) :
7003
+ methodScoping( scope, struct.val, struct ) :
6800
7004
  $.isPlainObject( struct.val ) ?
6801
7005
  {} :
6802
7006
  struct.val;
@@ -6892,11 +7096,6 @@
6892
7096
  src.propExt;
6893
7097
  }
6894
7098
  }
6895
-
6896
- // Rebuild the API with the new construct
6897
- if ( _Api.ready ) {
6898
- DataTable.api.build();
6899
- }
6900
7099
  };
6901
7100
 
6902
7101
 
@@ -6992,28 +7191,35 @@
6992
7191
  _api_registerPlural( 'tables().nodes()', 'table().node()' , function () {
6993
7192
  return this.iterator( 'table', function ( ctx ) {
6994
7193
  return ctx.nTable;
6995
- } );
7194
+ }, 1 );
6996
7195
  } );
6997
7196
 
6998
7197
 
6999
7198
  _api_registerPlural( 'tables().body()', 'table().body()' , function () {
7000
7199
  return this.iterator( 'table', function ( ctx ) {
7001
7200
  return ctx.nTBody;
7002
- } );
7201
+ }, 1 );
7003
7202
  } );
7004
7203
 
7005
7204
 
7006
7205
  _api_registerPlural( 'tables().header()', 'table().header()' , function () {
7007
7206
  return this.iterator( 'table', function ( ctx ) {
7008
7207
  return ctx.nTHead;
7009
- } );
7208
+ }, 1 );
7010
7209
  } );
7011
7210
 
7012
7211
 
7013
7212
  _api_registerPlural( 'tables().footer()', 'table().footer()' , function () {
7014
7213
  return this.iterator( 'table', function ( ctx ) {
7015
7214
  return ctx.nTFoot;
7016
- } );
7215
+ }, 1 );
7216
+ } );
7217
+
7218
+
7219
+ _api_registerPlural( 'tables().containers()', 'table().container()' , function () {
7220
+ return this.iterator( 'table', function ( ctx ) {
7221
+ return ctx.nTableWrapper;
7222
+ }, 1 );
7017
7223
  } );
7018
7224
 
7019
7225
 
@@ -7285,11 +7491,12 @@
7285
7491
  {
7286
7492
  var
7287
7493
  out = [], res,
7288
- a, i, ien, j, jen;
7494
+ a, i, ien, j, jen,
7495
+ selectorType = typeof selector;
7289
7496
 
7290
7497
  // Can't just check for isArray here, as an API or jQuery instance might be
7291
7498
  // given with their array like look
7292
- if ( ! selector || typeof selector === 'string' || selector.length === undefined ) {
7499
+ if ( ! selector || selectorType === 'string' || selectorType === 'function' || selector.length === undefined ) {
7293
7500
  selector = [ selector ];
7294
7501
  }
7295
7502
 
@@ -7399,7 +7606,7 @@
7399
7606
  tmp = $.inArray( i, displayFiltered );
7400
7607
 
7401
7608
  if ((tmp === -1 && search == 'removed') ||
7402
- (tmp === 1 && search == 'applied') )
7609
+ (tmp >= 0 && search == 'applied') )
7403
7610
  {
7404
7611
  a.push( i );
7405
7612
  }
@@ -7427,6 +7634,7 @@
7427
7634
  {
7428
7635
  return _selector_run( selector, function ( sel ) {
7429
7636
  var selInt = _intVal( sel );
7637
+ var i, ien;
7430
7638
 
7431
7639
  // Short cut - selector is a number and no options provided (default is
7432
7640
  // all records, so no need to check if the index is in there, since it
@@ -7446,17 +7654,24 @@
7446
7654
  return rows;
7447
7655
  }
7448
7656
 
7449
- // Get nodes in the order from the `rows` array (can't use `pluck`) @todo - use pluck_order
7450
- var nodes = [];
7451
- for ( var i=0, ien=rows.length ; i<ien ; i++ ) {
7452
- nodes.push( settings.aoData[ rows[i] ].nTr );
7657
+ // Selector - function
7658
+ if ( typeof sel === 'function' ) {
7659
+ return $.map( rows, function (idx) {
7660
+ var row = settings.aoData[ idx ];
7661
+ return sel( idx, row._aData, row.nTr ) ? idx : null;
7662
+ } );
7453
7663
  }
7454
7664
 
7665
+ // Get nodes in the order from the `rows` array with null values removed
7666
+ var nodes = _removeEmpty(
7667
+ _pluck_order( settings.aoData, rows, 'nTr' )
7668
+ );
7669
+
7670
+ // Selector - node
7455
7671
  if ( sel.nodeName ) {
7456
- // Selector - node
7457
7672
  if ( $.inArray( sel, nodes ) !== -1 ) {
7458
- return [ sel._DT_RowIndex ];// sel is a TR node that is in the table
7459
- // and DataTables adds a prop for fast lookup
7673
+ return [ sel._DT_RowIndex ]; // sel is a TR node that is in the table
7674
+ // and DataTables adds a prop for fast lookup
7460
7675
  }
7461
7676
  }
7462
7677
 
@@ -7490,7 +7705,7 @@
7490
7705
 
7491
7706
  var inst = this.iterator( 'table', function ( settings ) {
7492
7707
  return __row_selector( settings, selector, opts );
7493
- } );
7708
+ }, 1 );
7494
7709
 
7495
7710
  // Want argument shifting here and in __row_selector?
7496
7711
  inst.selector.rows = selector;
@@ -7503,32 +7718,32 @@
7503
7718
  _api_register( 'rows().nodes()', function () {
7504
7719
  return this.iterator( 'row', function ( settings, row ) {
7505
7720
  return settings.aoData[ row ].nTr || undefined;
7506
- } );
7721
+ }, 1 );
7507
7722
  } );
7508
7723
 
7509
7724
  _api_register( 'rows().data()', function () {
7510
7725
  return this.iterator( true, 'rows', function ( settings, rows ) {
7511
7726
  return _pluck_order( settings.aoData, rows, '_aData' );
7512
- } );
7727
+ }, 1 );
7513
7728
  } );
7514
7729
 
7515
7730
  _api_registerPlural( 'rows().cache()', 'row().cache()', function ( type ) {
7516
7731
  return this.iterator( 'row', function ( settings, row ) {
7517
7732
  var r = settings.aoData[ row ];
7518
7733
  return type === 'search' ? r._aFilterData : r._aSortData;
7519
- } );
7734
+ }, 1 );
7520
7735
  } );
7521
7736
 
7522
7737
  _api_registerPlural( 'rows().invalidate()', 'row().invalidate()', function ( src ) {
7523
7738
  return this.iterator( 'row', function ( settings, row ) {
7524
- _fnInvalidateRow( settings, row, src );
7739
+ _fnInvalidate( settings, row, src );
7525
7740
  } );
7526
7741
  } );
7527
7742
 
7528
7743
  _api_registerPlural( 'rows().indexes()', 'row().index()', function () {
7529
7744
  return this.iterator( 'row', function ( settings, row ) {
7530
7745
  return row;
7531
- } );
7746
+ }, 1 );
7532
7747
  } );
7533
7748
 
7534
7749
  _api_registerPlural( 'rows().remove()', 'row().remove()', function () {
@@ -7577,7 +7792,7 @@
7577
7792
  }
7578
7793
 
7579
7794
  return out;
7580
- } );
7795
+ }, 1 );
7581
7796
 
7582
7797
  // Return an Api.rows() extended instance, so rows().nodes() etc can be used
7583
7798
  var modRows = this.rows( -1 );
@@ -7613,7 +7828,7 @@
7613
7828
  ctx[0].aoData[ this[0] ]._aData = data;
7614
7829
 
7615
7830
  // Automatically invalidate
7616
- _fnInvalidateRow( ctx[0], this[0], 'data' );
7831
+ _fnInvalidate( ctx[0], this[0], 'data' );
7617
7832
 
7618
7833
  return this;
7619
7834
  } );
@@ -7660,7 +7875,7 @@
7660
7875
  }
7661
7876
  else {
7662
7877
  // Otherwise create a row with a wrapper
7663
- var created = $('<tr><td/></tr>');
7878
+ var created = $('<tr><td/></tr>').addClass( k );
7664
7879
  $('td', created)
7665
7880
  .addClass( k )
7666
7881
  .html( r )
@@ -7692,26 +7907,42 @@
7692
7907
  };
7693
7908
 
7694
7909
 
7695
- var __details_display = function ( show ) {
7696
- var ctx = this.context;
7910
+ var __details_remove = function ( api, idx )
7911
+ {
7912
+ var ctx = api.context;
7913
+
7914
+ if ( ctx.length ) {
7915
+ var row = ctx[0].aoData[ idx !== undefined ? idx : api[0] ];
7916
+
7917
+ if ( row._details ) {
7918
+ row._details.remove();
7919
+
7920
+ row._detailsShow = undefined;
7921
+ row._details = undefined;
7922
+ }
7923
+ }
7924
+ };
7697
7925
 
7698
- if ( ctx.length && this.length ) {
7699
- var row = ctx[0].aoData[ this[0] ];
7926
+
7927
+ var __details_display = function ( api, show ) {
7928
+ var ctx = api.context;
7929
+
7930
+ if ( ctx.length && api.length ) {
7931
+ var row = ctx[0].aoData[ api[0] ];
7700
7932
 
7701
7933
  if ( row._details ) {
7702
7934
  row._detailsShow = show;
7935
+
7703
7936
  if ( show ) {
7704
7937
  row._details.insertAfter( row.nTr );
7705
7938
  }
7706
7939
  else {
7707
- row._details.remove();
7940
+ row._details.detach();
7708
7941
  }
7709
7942
 
7710
7943
  __details_events( ctx[0] );
7711
7944
  }
7712
7945
  }
7713
-
7714
- return this;
7715
7946
  };
7716
7947
 
7717
7948
 
@@ -7721,15 +7952,21 @@
7721
7952
  var namespace = '.dt.DT_details';
7722
7953
  var drawEvent = 'draw'+namespace;
7723
7954
  var colvisEvent = 'column-visibility'+namespace;
7955
+ var destroyEvent = 'destroy'+namespace;
7956
+ var data = settings.aoData;
7724
7957
 
7725
- api.off( drawEvent +' '+ colvisEvent );
7958
+ api.off( drawEvent +' '+ colvisEvent +' '+ destroyEvent );
7726
7959
 
7727
- if ( _pluck( settings.aoData, '_details' ).length > 0 ) {
7960
+ if ( _pluck( data, '_details' ).length > 0 ) {
7728
7961
  // On each draw, insert the required elements into the document
7729
- api.on( drawEvent, function () {
7962
+ api.on( drawEvent, function ( e, ctx ) {
7963
+ if ( settings !== ctx ) {
7964
+ return;
7965
+ }
7966
+
7730
7967
  api.rows( {page:'current'} ).eq(0).each( function (idx) {
7731
7968
  // Internal data grab
7732
- var row = settings.aoData[ idx ];
7969
+ var row = data[ idx ];
7733
7970
 
7734
7971
  if ( row._detailsShow ) {
7735
7972
  row._details.insertAfter( row.nTr );
@@ -7738,27 +7975,49 @@
7738
7975
  } );
7739
7976
 
7740
7977
  // Column visibility change - update the colspan
7741
- api.on( colvisEvent, function ( e, settings, idx, vis ) {
7978
+ api.on( colvisEvent, function ( e, ctx, idx, vis ) {
7979
+ if ( settings !== ctx ) {
7980
+ return;
7981
+ }
7982
+
7742
7983
  // Update the colspan for the details rows (note, only if it already has
7743
7984
  // a colspan)
7744
- var row, visible = _fnVisbleColumns( settings );
7985
+ var row, visible = _fnVisbleColumns( ctx );
7745
7986
 
7746
- for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
7747
- row = settings.aoData[i];
7987
+ for ( var i=0, ien=data.length ; i<ien ; i++ ) {
7988
+ row = data[i];
7748
7989
 
7749
7990
  if ( row._details ) {
7750
7991
  row._details.children('td[colspan]').attr('colspan', visible );
7751
7992
  }
7752
7993
  }
7753
7994
  } );
7995
+
7996
+ // Table destroyed - nuke any child rows
7997
+ api.on( destroyEvent, function ( e, ctx ) {
7998
+ if ( settings !== ctx ) {
7999
+ return;
8000
+ }
8001
+
8002
+ for ( var i=0, ien=data.length ; i<ien ; i++ ) {
8003
+ if ( data[i]._details ) {
8004
+ __details_remove( api, i );
8005
+ }
8006
+ }
8007
+ } );
7754
8008
  }
7755
8009
  };
7756
8010
 
8011
+ // Strings for the method names to help minification
8012
+ var _emp = '';
8013
+ var _child_obj = _emp+'row().child';
8014
+ var _child_mth = _child_obj+'()';
8015
+
7757
8016
  // data can be:
7758
8017
  // tr
7759
8018
  // string
7760
8019
  // jQuery or array of any of the above
7761
- _api_register( 'row().child()', function ( data, klass ) {
8020
+ _api_register( _child_mth, function ( data, klass ) {
7762
8021
  var ctx = this.context;
7763
8022
 
7764
8023
  if ( data === undefined ) {
@@ -7767,6 +8026,14 @@
7767
8026
  ctx[0].aoData[ this[0] ]._details :
7768
8027
  undefined;
7769
8028
  }
8029
+ else if ( data === true ) {
8030
+ // show
8031
+ this.child.show();
8032
+ }
8033
+ else if ( data === false ) {
8034
+ // remove
8035
+ __details_remove( this );
8036
+ }
7770
8037
  else if ( ctx.length && this.length ) {
7771
8038
  // set
7772
8039
  __details_add( ctx[0], ctx[0].aoData[ this[0] ], data, klass );
@@ -7775,23 +8042,35 @@
7775
8042
  return this;
7776
8043
  } );
7777
8044
 
8045
+
8046
+ _api_register( [
8047
+ _child_obj+'.show()',
8048
+ _child_mth+'.show()' // only when `child()` was called with parameters (without
8049
+ ], function ( show ) { // it returns an object and this method is not executed)
8050
+ __details_display( this, true );
8051
+ return this;
8052
+ } );
8053
+
8054
+
7778
8055
  _api_register( [
7779
- 'row().child.show()',
7780
- 'row().child().show()'
7781
- ], function () {
7782
- __details_display.call( this, true );
8056
+ _child_obj+'.hide()',
8057
+ _child_mth+'.hide()' // only when `child()` was called with parameters (without
8058
+ ], function () { // it returns an object and this method is not executed)
8059
+ __details_display( this, false );
7783
8060
  return this;
7784
8061
  } );
7785
8062
 
8063
+
7786
8064
  _api_register( [
7787
- 'row().child.hide()',
7788
- 'row().child().hide()'
7789
- ], function () {
7790
- __details_display.call( this, false );
8065
+ _child_obj+'.remove()',
8066
+ _child_mth+'.remove()' // only when `child()` was called with parameters (without
8067
+ ], function () { // it returns an object and this method is not executed)
8068
+ __details_remove( this );
7791
8069
  return this;
7792
8070
  } );
7793
8071
 
7794
- _api_register( 'row().child.isShown()', function () {
8072
+
8073
+ _api_register( _child_obj+'.isShown()', function () {
7795
8074
  var ctx = this.context;
7796
8075
 
7797
8076
  if ( ctx.length && this.length ) {
@@ -7817,7 +8096,19 @@
7817
8096
  // can be an array of these items, comma separated list, or an array of comma
7818
8097
  // separated lists
7819
8098
 
7820
- var __re_column_selector = /^(.*):(name|visIdx|visible)$/;
8099
+ var __re_column_selector = /^(.+):(name|visIdx|visible)$/;
8100
+
8101
+
8102
+ // r1 and r2 are redundant - but it means that the parameters match for the
8103
+ // iterator callback in columns().data()
8104
+ var __columnData = function ( settings, column, r1, r2, rows ) {
8105
+ var a = [];
8106
+ for ( var row=0, ien=rows.length ; row<ien ; row++ ) {
8107
+ a.push( _fnGetCellData( settings, rows[row], column ) );
8108
+ }
8109
+ return a;
8110
+ };
8111
+
7821
8112
 
7822
8113
  var __column_selector = function ( settings, selector, opts )
7823
8114
  {
@@ -7829,63 +8120,74 @@
7829
8120
  return _selector_run( selector, function ( s ) {
7830
8121
  var selInt = _intVal( s );
7831
8122
 
8123
+ // Selector - all
7832
8124
  if ( s === '' ) {
7833
- // All columns
7834
8125
  return _range( columns.length );
7835
8126
  }
7836
- else if ( selInt !== null ) {
7837
- // Integer selector
8127
+
8128
+ // Selector - index
8129
+ if ( selInt !== null ) {
7838
8130
  return [ selInt >= 0 ?
7839
8131
  selInt : // Count from left
7840
8132
  columns.length + selInt // Count from right (+ because its a negative value)
7841
8133
  ];
7842
8134
  }
7843
- else {
7844
- var match = typeof s === 'string' ?
7845
- s.match( __re_column_selector ) :
7846
- '';
7847
8135
 
7848
- if ( match ) {
7849
- switch( match[2] ) {
7850
- case 'visIdx':
7851
- case 'visible':
7852
- var idx = parseInt( match[1], 10 );
7853
- // Visible index given, convert to column index
7854
- if ( idx < 0 ) {
7855
- // Counting from the right
7856
- var visColumns = $.map( columns, function (col,i) {
7857
- return col.bVisible ? i : null;
7858
- } );
7859
- return [ visColumns[ visColumns.length + idx ] ];
7860
- }
7861
- // Counting from the left
7862
- return [ _fnVisibleToColumnIndex( settings, idx ) ];
8136
+ // Selector = function
8137
+ if ( typeof s === 'function' ) {
8138
+ var rows = _selector_row_indexes( settings, opts );
8139
+
8140
+ return $.map( columns, function (col, idx) {
8141
+ return s(
8142
+ idx,
8143
+ __columnData( settings, idx, 0, 0, rows ),
8144
+ nodes[ idx ]
8145
+ ) ? idx : null;
8146
+ } );
8147
+ }
7863
8148
 
7864
- case 'name':
7865
- // match by name. `names` is column index complete and in order
7866
- return $.map( names, function (name, i) {
7867
- return name === match[1] ? i : null;
8149
+ // jQuery or string selector
8150
+ var match = typeof s === 'string' ?
8151
+ s.match( __re_column_selector ) :
8152
+ '';
8153
+
8154
+ if ( match ) {
8155
+ switch( match[2] ) {
8156
+ case 'visIdx':
8157
+ case 'visible':
8158
+ var idx = parseInt( match[1], 10 );
8159
+ // Visible index given, convert to column index
8160
+ if ( idx < 0 ) {
8161
+ // Counting from the right
8162
+ var visColumns = $.map( columns, function (col,i) {
8163
+ return col.bVisible ? i : null;
7868
8164
  } );
7869
- }
7870
- }
7871
- else {
7872
- // jQuery selector on the TH elements for the columns
7873
- return $( nodes )
7874
- .filter( s )
7875
- .map( function () {
7876
- return $.inArray( this, nodes ); // `nodes` is column index complete and in order
7877
- } )
7878
- .toArray();
8165
+ return [ visColumns[ visColumns.length + idx ] ];
8166
+ }
8167
+ // Counting from the left
8168
+ return [ _fnVisibleToColumnIndex( settings, idx ) ];
8169
+
8170
+ case 'name':
8171
+ // match by name. `names` is column index complete and in order
8172
+ return $.map( names, function (name, i) {
8173
+ return name === match[1] ? i : null;
8174
+ } );
7879
8175
  }
7880
8176
  }
8177
+ else {
8178
+ // jQuery selector on the TH elements for the columns
8179
+ return $( nodes )
8180
+ .filter( s )
8181
+ .map( function () {
8182
+ return $.inArray( this, nodes ); // `nodes` is column index complete and in order
8183
+ } )
8184
+ .toArray();
8185
+ }
7881
8186
  } );
7882
8187
  };
7883
8188
 
7884
8189
 
7885
-
7886
-
7887
-
7888
- var __setColumnVis = function ( settings, column, vis ) {
8190
+ var __setColumnVis = function ( settings, column, vis, recalc ) {
7889
8191
  var
7890
8192
  cols = settings.aoColumns,
7891
8193
  col = cols[ column ],
@@ -7921,12 +8223,6 @@
7921
8223
  else {
7922
8224
  // Remove column
7923
8225
  $( _pluck( settings.aoData, 'anCells', column ) ).detach();
7924
-
7925
- col.bVisible = false;
7926
- _fnDrawHead( settings, settings.aoHeader );
7927
- _fnDrawHead( settings, settings.aoFooter );
7928
-
7929
- _fnSaveState( settings );
7930
8226
  }
7931
8227
 
7932
8228
  // Common actions
@@ -7934,12 +8230,14 @@
7934
8230
  _fnDrawHead( settings, settings.aoHeader );
7935
8231
  _fnDrawHead( settings, settings.aoFooter );
7936
8232
 
7937
- // Automatically adjust column sizing
7938
- _fnAdjustColumnSizing( settings );
8233
+ if ( recalc === undefined || recalc ) {
8234
+ // Automatically adjust column sizing
8235
+ _fnAdjustColumnSizing( settings );
7939
8236
 
7940
- // Realign columns for scrolling
7941
- if ( settings.oScroll.sX || settings.oScroll.sY ) {
7942
- _fnScrollDraw( settings );
8237
+ // Realign columns for scrolling
8238
+ if ( settings.oScroll.sX || settings.oScroll.sY ) {
8239
+ _fnScrollDraw( settings );
8240
+ }
7943
8241
  }
7944
8242
 
7945
8243
  _fnCallbackFire( settings, null, 'column-visibility', [settings, column, vis] );
@@ -7965,7 +8263,7 @@
7965
8263
 
7966
8264
  var inst = this.iterator( 'table', function ( settings ) {
7967
8265
  return __column_selector( settings, selector, opts );
7968
- } );
8266
+ }, 1 );
7969
8267
 
7970
8268
  // Want argument shifting here and in _row_selector?
7971
8269
  inst.selector.cols = selector;
@@ -7981,7 +8279,7 @@
7981
8279
  _api_registerPlural( 'columns().header()', 'column().header()', function ( selector, opts ) {
7982
8280
  return this.iterator( 'column', function ( settings, column ) {
7983
8281
  return settings.aoColumns[column].nTh;
7984
- } );
8282
+ }, 1 );
7985
8283
  } );
7986
8284
 
7987
8285
 
@@ -7991,7 +8289,7 @@
7991
8289
  _api_registerPlural( 'columns().footer()', 'column().footer()', function ( selector, opts ) {
7992
8290
  return this.iterator( 'column', function ( settings, column ) {
7993
8291
  return settings.aoColumns[column].nTf;
7994
- } );
8292
+ }, 1 );
7995
8293
  } );
7996
8294
 
7997
8295
 
@@ -7999,13 +8297,14 @@
7999
8297
  *
8000
8298
  */
8001
8299
  _api_registerPlural( 'columns().data()', 'column().data()', function () {
8002
- return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {
8003
- var a = [];
8004
- for ( var row=0, ien=rows.length ; row<ien ; row++ ) {
8005
- a.push( _fnGetCellData( settings, rows[row], column, '' ) );
8006
- }
8007
- return a;
8008
- } );
8300
+ return this.iterator( 'column-rows', __columnData, 1 );
8301
+ } );
8302
+
8303
+
8304
+ _api_registerPlural( 'columns().dataSrc()', 'column().dataSrc()', function () {
8305
+ return this.iterator( 'column', function ( settings, column ) {
8306
+ return settings.aoColumns[column].mData;
8307
+ }, 1 );
8009
8308
  } );
8010
8309
 
8011
8310
 
@@ -8014,23 +8313,24 @@
8014
8313
  return _pluck_order( settings.aoData, rows,
8015
8314
  type === 'search' ? '_aFilterData' : '_aSortData', column
8016
8315
  );
8017
- } );
8316
+ }, 1 );
8018
8317
  } );
8019
8318
 
8020
8319
 
8021
8320
  _api_registerPlural( 'columns().nodes()', 'column().nodes()', function () {
8022
8321
  return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {
8023
8322
  return _pluck_order( settings.aoData, rows, 'anCells', column ) ;
8024
- } );
8323
+ }, 1 );
8025
8324
  } );
8026
8325
 
8027
8326
 
8028
8327
 
8029
- _api_registerPlural( 'columns().visible()', 'column().visible()', function ( vis ) {
8328
+ _api_registerPlural( 'columns().visible()', 'column().visible()', function ( vis, calc ) {
8030
8329
  return this.iterator( 'column', function ( settings, column ) {
8031
- return vis === undefined ?
8032
- settings.aoColumns[ column ].bVisible :
8033
- __setColumnVis( settings, column, vis );
8330
+ if ( vis === undefined ) {
8331
+ return settings.aoColumns[ column ].bVisible;
8332
+ } // else
8333
+ __setColumnVis( settings, column, vis, calc );
8034
8334
  } );
8035
8335
  } );
8036
8336
 
@@ -8041,7 +8341,7 @@
8041
8341
  return type === 'visible' ?
8042
8342
  _fnColumnIndexToVisible( settings, column ) :
8043
8343
  column;
8044
- } );
8344
+ }, 1 );
8045
8345
  } );
8046
8346
 
8047
8347
 
@@ -8061,7 +8361,7 @@
8061
8361
  _api_register( 'columns.adjust()', function () {
8062
8362
  return this.iterator( 'table', function ( settings ) {
8063
8363
  _fnAdjustColumnSizing( settings );
8064
- } );
8364
+ }, 1 );
8065
8365
  } );
8066
8366
 
8067
8367
 
@@ -8091,35 +8391,52 @@
8091
8391
  {
8092
8392
  var data = settings.aoData;
8093
8393
  var rows = _selector_row_indexes( settings, opts );
8094
- var cells = _pluck_order( data, rows, 'anCells' );
8394
+ var cells = _removeEmpty( _pluck_order( data, rows, 'anCells' ) );
8095
8395
  var allCells = $( [].concat.apply([], cells) );
8096
8396
  var row;
8097
8397
  var columns = settings.aoColumns.length;
8098
- var a, i, ien, j;
8398
+ var a, i, ien, j, o, host;
8099
8399
 
8100
8400
  return _selector_run( selector, function ( s ) {
8101
- if ( ! s ) {
8102
- // All cells
8401
+ var fnSelector = typeof s === 'function';
8402
+
8403
+ if ( s === null || s === undefined || fnSelector ) {
8404
+ // All cells and function selectors
8103
8405
  a = [];
8104
8406
 
8105
8407
  for ( i=0, ien=rows.length ; i<ien ; i++ ) {
8106
8408
  row = rows[i];
8107
8409
 
8108
8410
  for ( j=0 ; j<columns ; j++ ) {
8109
- a.push( {
8411
+ o = {
8110
8412
  row: row,
8111
8413
  column: j
8112
- } );
8414
+ };
8415
+
8416
+ if ( fnSelector ) {
8417
+ // Selector - function
8418
+ host = settings.aoData[ row ];
8419
+
8420
+ if ( s( o, _fnGetCellData(settings, row, j), host.anCells[j] ) ) {
8421
+ a.push( o );
8422
+ }
8423
+ }
8424
+ else {
8425
+ // Selector - all
8426
+ a.push( o );
8427
+ }
8113
8428
  }
8114
8429
  }
8115
8430
 
8116
8431
  return a;
8117
8432
  }
8118
- else if ( $.isPlainObject( s ) ) {
8433
+
8434
+ // Selector - index
8435
+ if ( $.isPlainObject( s ) ) {
8119
8436
  return [s];
8120
8437
  }
8121
8438
 
8122
- // jQuery filtered cells
8439
+ // Selector - jQuery filtered cells
8123
8440
  return allCells
8124
8441
  .filter( s )
8125
8442
  .map( function (i, el) {
@@ -8140,8 +8457,8 @@
8140
8457
  _api_register( 'cells()', function ( rowSelector, columnSelector, opts ) {
8141
8458
  // Argument shifting
8142
8459
  if ( $.isPlainObject( rowSelector ) ) {
8143
- // If passing in a cell index
8144
- if ( rowSelector.row ) {
8460
+ // Indexes
8461
+ if ( typeof rowSelector.row !== undefined ) {
8145
8462
  opts = columnSelector;
8146
8463
  columnSelector = null;
8147
8464
  }
@@ -8180,7 +8497,7 @@
8180
8497
  }
8181
8498
 
8182
8499
  return a;
8183
- } );
8500
+ }, 1 );
8184
8501
 
8185
8502
  $.extend( cells.selector, {
8186
8503
  cols: columnSelector,
@@ -8194,15 +8511,18 @@
8194
8511
 
8195
8512
  _api_registerPlural( 'cells().nodes()', 'cell().node()', function () {
8196
8513
  return this.iterator( 'cell', function ( settings, row, column ) {
8197
- return settings.aoData[ row ].anCells[ column ];
8198
- } );
8514
+ var cells = settings.aoData[ row ].anCells;
8515
+ return cells ?
8516
+ cells[ column ] :
8517
+ undefined;
8518
+ }, 1 );
8199
8519
  } );
8200
8520
 
8201
8521
 
8202
8522
  _api_register( 'cells().data()', function () {
8203
8523
  return this.iterator( 'cell', function ( settings, row, column ) {
8204
8524
  return _fnGetCellData( settings, row, column );
8205
- } );
8525
+ }, 1 );
8206
8526
  } );
8207
8527
 
8208
8528
 
@@ -8211,44 +8531,41 @@
8211
8531
 
8212
8532
  return this.iterator( 'cell', function ( settings, row, column ) {
8213
8533
  return settings.aoData[ row ][ type ][ column ];
8214
- } );
8534
+ }, 1 );
8215
8535
  } );
8216
8536
 
8217
8537
 
8218
- _api_registerPlural( 'cells().indexes()', 'cell().index()', function () {
8538
+ _api_registerPlural( 'cells().render()', 'cell().render()', function ( type ) {
8219
8539
  return this.iterator( 'cell', function ( settings, row, column ) {
8220
- return {
8540
+ return _fnGetCellData( settings, row, column, type );
8541
+ }, 1 );
8542
+ } );
8543
+
8544
+
8545
+ _api_registerPlural( 'cells().indexes()', 'cell().index()', function () {
8546
+ return this.iterator( 'cell', function ( settings, row, column ) {
8547
+ return {
8221
8548
  row: row,
8222
8549
  column: column,
8223
8550
  columnVisible: _fnColumnIndexToVisible( settings, column )
8224
8551
  };
8225
- } );
8552
+ }, 1 );
8226
8553
  } );
8227
8554
 
8228
8555
 
8229
- _api_register( [
8230
- 'cells().invalidate()',
8231
- 'cell().invalidate()'
8232
- ], function ( src ) {
8233
- var selector = this.selector;
8234
-
8235
- // Use the rows method of the instance to perform the invalidation, rather
8236
- // than doing it here. This avoids needing to handle duplicate rows from
8237
- // the cells.
8238
- this.rows( selector.rows, selector.opts ).invalidate( src );
8239
-
8240
- return this;
8556
+ _api_registerPlural( 'cells().invalidate()', 'cell().invalidate()', function ( src ) {
8557
+ return this.iterator( 'cell', function ( settings, row, column ) {
8558
+ _fnInvalidate( settings, row, src, column );
8559
+ } );
8241
8560
  } );
8242
8561
 
8243
8562
 
8244
8563
 
8245
-
8246
8564
  _api_register( 'cell()', function ( rowSelector, columnSelector, opts ) {
8247
8565
  return _selector_first( this.cells( rowSelector, columnSelector, opts ) );
8248
8566
  } );
8249
8567
 
8250
8568
 
8251
-
8252
8569
  _api_register( 'cell().data()', function ( data ) {
8253
8570
  var ctx = this.context;
8254
8571
  var cell = this[0];
@@ -8262,7 +8579,7 @@
8262
8579
 
8263
8580
  // Set
8264
8581
  _fnSetCellData( ctx[0], cell[0].row, cell[0].column, data );
8265
- _fnInvalidateRow( ctx[0], cell[0].row, 'data', cell[0].column );
8582
+ _fnInvalidate( ctx[0], cell[0].row, 'data', cell[0].column );
8266
8583
 
8267
8584
  return this;
8268
8585
  } );
@@ -8387,31 +8704,64 @@
8387
8704
  } );
8388
8705
 
8389
8706
 
8390
- _api_register( [
8707
+ _api_registerPlural(
8391
8708
  'columns().search()',
8392
- 'column().search()'
8393
- ], function ( input, regex, smart, caseInsen ) {
8394
- return this.iterator( 'column', function ( settings, column ) {
8395
- var preSearch = settings.aoPreSearchCols;
8709
+ 'column().search()',
8710
+ function ( input, regex, smart, caseInsen ) {
8711
+ return this.iterator( 'column', function ( settings, column ) {
8712
+ var preSearch = settings.aoPreSearchCols;
8713
+
8714
+ if ( input === undefined ) {
8715
+ // get
8716
+ return preSearch[ column ].sSearch;
8717
+ }
8396
8718
 
8397
- if ( input === undefined ) {
8398
- // get
8399
- return preSearch[ column ].sSearch;
8400
- }
8719
+ // set
8720
+ if ( ! settings.oFeatures.bFilter ) {
8721
+ return;
8722
+ }
8401
8723
 
8402
- // set
8403
- if ( ! settings.oFeatures.bFilter ) {
8404
- return;
8405
- }
8724
+ $.extend( preSearch[ column ], {
8725
+ "sSearch": input+"",
8726
+ "bRegex": regex === null ? false : regex,
8727
+ "bSmart": smart === null ? true : smart,
8728
+ "bCaseInsensitive": caseInsen === null ? true : caseInsen
8729
+ } );
8406
8730
 
8407
- $.extend( preSearch[ column ], {
8408
- "sSearch": input+"",
8409
- "bRegex": regex === null ? false : regex,
8410
- "bSmart": smart === null ? true : smart,
8411
- "bCaseInsensitive": caseInsen === null ? true : caseInsen
8731
+ _fnFilterComplete( settings, settings.oPreviousSearch, 1 );
8412
8732
  } );
8733
+ }
8734
+ );
8735
+
8736
+ /*
8737
+ * State API methods
8738
+ */
8413
8739
 
8414
- _fnFilterComplete( settings, settings.oPreviousSearch, 1 );
8740
+ _api_register( 'state()', function () {
8741
+ return this.context.length ?
8742
+ this.context[0].oSavedState :
8743
+ null;
8744
+ } );
8745
+
8746
+
8747
+ _api_register( 'state.clear()', function () {
8748
+ return this.iterator( 'table', function ( settings ) {
8749
+ // Save an empty object
8750
+ settings.fnStateSaveCallback.call( settings.oInstance, settings, {} );
8751
+ } );
8752
+ } );
8753
+
8754
+
8755
+ _api_register( 'state.loaded()', function () {
8756
+ return this.context.length ?
8757
+ this.context[0].oLoadedState :
8758
+ null;
8759
+ } );
8760
+
8761
+
8762
+ _api_register( 'state.save()', function () {
8763
+ return this.iterator( 'table', function ( settings ) {
8764
+ _fnSaveState( settings );
8415
8765
  } );
8416
8766
  } );
8417
8767
 
@@ -8503,7 +8853,7 @@
8503
8853
  */
8504
8854
  DataTable.tables = DataTable.fnTables = function ( visible )
8505
8855
  {
8506
- return jQuery.map( DataTable.settings, function (o) {
8856
+ return $.map( DataTable.settings, function (o) {
8507
8857
  if ( !visible || (visible && $(o.nTable).is(':visible')) ) {
8508
8858
  return o.nTable;
8509
8859
  }
@@ -8511,6 +8861,38 @@
8511
8861
  };
8512
8862
 
8513
8863
 
8864
+ /**
8865
+ * DataTables utility methods
8866
+ *
8867
+ * This namespace provides helper methods that DataTables uses internally to
8868
+ * create a DataTable, but which are not exclusively used only for DataTables.
8869
+ * These methods can be used by extension authors to save the duplication of
8870
+ * code.
8871
+ *
8872
+ * @namespace
8873
+ */
8874
+ DataTable.util = {
8875
+ /**
8876
+ * Throttle the calls to a function. Arguments and context are maintained
8877
+ * for the throttled function.
8878
+ *
8879
+ * @param {function} fn Function to be called
8880
+ * @param {integer} freq Call frequency in mS
8881
+ * @return {function} Wrapped function
8882
+ */
8883
+ throttle: _fnThrottle,
8884
+
8885
+
8886
+ /**
8887
+ * Escape a string such that it can be used in a regular expression
8888
+ *
8889
+ * @param {string} sVal string to escape
8890
+ * @returns {string} escaped string
8891
+ */
8892
+ escapeRegex: _fnEscapeRegex
8893
+ };
8894
+
8895
+
8514
8896
  /**
8515
8897
  * Convert from camel case parameters to Hungarian notation. This is made public
8516
8898
  * for the extensions to provide the same ability as DataTables core to accept
@@ -8549,7 +8931,7 @@
8549
8931
  var args = Array.prototype.slice.call(arguments);
8550
8932
 
8551
8933
  // Add the `dt` namespace automatically if it isn't already present
8552
- if ( args[0].indexOf( '.dt' ) === -1 ) {
8934
+ if ( ! args[0].match(/\.dt\b/) ) {
8553
8935
  args[0] += '.dt';
8554
8936
  }
8555
8937
 
@@ -8690,7 +9072,7 @@
8690
9072
  * @type string
8691
9073
  * @default Version number
8692
9074
  */
8693
- DataTable.version = "1.10.0";
9075
+ DataTable.version = "1.10.4";
8694
9076
 
8695
9077
  /**
8696
9078
  * Private data store, containing all of the settings objects that are
@@ -10953,6 +11335,17 @@
10953
11335
  "sSearch": "Search:",
10954
11336
 
10955
11337
 
11338
+ /**
11339
+ * Assign a `placeholder` attribute to the search `input` element
11340
+ * @type string
11341
+ * @default
11342
+ *
11343
+ * @dtopt Language
11344
+ * @name DataTable.defaults.language.searchPlaceholder
11345
+ */
11346
+ "sSearchPlaceholder": "",
11347
+
11348
+
10956
11349
  /**
10957
11350
  * All of the language information can be stored in a file on the
10958
11351
  * server-side, which DataTables will look up if this parameter is passed.
@@ -11119,6 +11512,26 @@
11119
11512
  "sDom": "lfrtip",
11120
11513
 
11121
11514
 
11515
+ /**
11516
+ * Search delay option. This will throttle full table searches that use the
11517
+ * DataTables provided search input element (it does not effect calls to
11518
+ * `dt-api search()`, providing a delay before the search is made.
11519
+ * @type integer
11520
+ * @default 0
11521
+ *
11522
+ * @dtopt Options
11523
+ * @name DataTable.defaults.searchDelay
11524
+ *
11525
+ * @example
11526
+ * $(document).ready( function() {
11527
+ * $('#example').dataTable( {
11528
+ * "searchDelay": 200
11529
+ * } );
11530
+ * } )
11531
+ */
11532
+ "searchDelay": null,
11533
+
11534
+
11122
11535
  /**
11123
11536
  * DataTables features four different built-in options for the buttons to
11124
11537
  * display for pagination control:
@@ -12635,6 +13048,13 @@
12635
13048
  */
12636
13049
  "sDom": null,
12637
13050
 
13051
+ /**
13052
+ * Search delay (in mS)
13053
+ * @type integer
13054
+ * @default null
13055
+ */
13056
+ "searchDelay": null,
13057
+
12638
13058
  /**
12639
13059
  * Which type of pagination should be used.
12640
13060
  * Note that this parameter will be set by the initialisation routine. To
@@ -12681,6 +13101,13 @@
12681
13101
  */
12682
13102
  "aoStateLoad": [],
12683
13103
 
13104
+ /**
13105
+ * State that was saved. Useful for back reference
13106
+ * @type object
13107
+ * @default null
13108
+ */
13109
+ "oSavedState": null,
13110
+
12684
13111
  /**
12685
13112
  * State that was loaded. Useful for back reference
12686
13113
  * @type object
@@ -13668,6 +14095,7 @@
13668
14095
  numbers_length: 7
13669
14096
  } );
13670
14097
 
14098
+
13671
14099
  $.extend( true, DataTable.ext.renderer, {
13672
14100
  pageButton: {
13673
14101
  _: function ( settings, host, idx, buttons, page, pages ) {
@@ -13752,25 +14180,116 @@
13752
14180
  }
13753
14181
  };
13754
14182
 
13755
- // Because this approach is destroying and recreating the paging
13756
- // elements, focus is lost on the select button which is bad for
13757
- // accessibility. So we want to restore focus once the draw has
13758
- // completed
13759
- var activeEl = $(document.activeElement).data('dt-idx');
14183
+ // IE9 throws an 'unknown error' if document.activeElement is used
14184
+ // inside an iframe or frame. Try / catch the error. Not good for
14185
+ // accessibility, but neither are frames.
14186
+ try {
14187
+ // Because this approach is destroying and recreating the paging
14188
+ // elements, focus is lost on the select button which is bad for
14189
+ // accessibility. So we want to restore focus once the draw has
14190
+ // completed
14191
+ var activeEl = $(document.activeElement).data('dt-idx');
13760
14192
 
13761
- attach( $(host).empty(), buttons );
14193
+ attach( $(host).empty(), buttons );
13762
14194
 
13763
- if ( activeEl !== null ) {
13764
- $(host).find( '[data-dt-idx='+activeEl+']' ).focus();
14195
+ if ( activeEl !== null ) {
14196
+ $(host).find( '[data-dt-idx='+activeEl+']' ).focus();
14197
+ }
13765
14198
  }
14199
+ catch (e) {}
13766
14200
  }
13767
14201
  }
13768
14202
  } );
13769
14203
 
13770
14204
 
13771
14205
 
14206
+ // Built in type detection. See model.ext.aTypes for information about
14207
+ // what is required from this methods.
14208
+ $.extend( DataTable.ext.type.detect, [
14209
+ // Plain numbers - first since V8 detects some plain numbers as dates
14210
+ // e.g. Date.parse('55') (but not all, e.g. Date.parse('22')...).
14211
+ function ( d, settings )
14212
+ {
14213
+ var decimal = settings.oLanguage.sDecimal;
14214
+ return _isNumber( d, decimal ) ? 'num'+decimal : null;
14215
+ },
14216
+
14217
+ // Dates (only those recognised by the browser's Date.parse)
14218
+ function ( d, settings )
14219
+ {
14220
+ // V8 will remove any unknown characters at the start and end of the
14221
+ // expression, leading to false matches such as `$245.12` or `10%` being
14222
+ // a valid date. See forum thread 18941 for detail.
14223
+ if ( d && !(d instanceof Date) && ( ! _re_date_start.test(d) || ! _re_date_end.test(d) ) ) {
14224
+ return null;
14225
+ }
14226
+ var parsed = Date.parse(d);
14227
+ return (parsed !== null && !isNaN(parsed)) || _empty(d) ? 'date' : null;
14228
+ },
14229
+
14230
+ // Formatted numbers
14231
+ function ( d, settings )
14232
+ {
14233
+ var decimal = settings.oLanguage.sDecimal;
14234
+ return _isNumber( d, decimal, true ) ? 'num-fmt'+decimal : null;
14235
+ },
14236
+
14237
+ // HTML numeric
14238
+ function ( d, settings )
14239
+ {
14240
+ var decimal = settings.oLanguage.sDecimal;
14241
+ return _htmlNumeric( d, decimal ) ? 'html-num'+decimal : null;
14242
+ },
14243
+
14244
+ // HTML numeric, formatted
14245
+ function ( d, settings )
14246
+ {
14247
+ var decimal = settings.oLanguage.sDecimal;
14248
+ return _htmlNumeric( d, decimal, true ) ? 'html-num-fmt'+decimal : null;
14249
+ },
14250
+
14251
+ // HTML (this is strict checking - there must be html)
14252
+ function ( d, settings )
14253
+ {
14254
+ return _empty( d ) || (typeof d === 'string' && d.indexOf('<') !== -1) ?
14255
+ 'html' : null;
14256
+ }
14257
+ ] );
14258
+
14259
+
14260
+
14261
+ // Filter formatting functions. See model.ext.ofnSearch for information about
14262
+ // what is required from these methods.
14263
+ //
14264
+ // Note that additional search methods are added for the html numbers and
14265
+ // html formatted numbers by `_addNumericSort()` when we know what the decimal
14266
+ // place is
14267
+
14268
+
14269
+ $.extend( DataTable.ext.type.search, {
14270
+ html: function ( data ) {
14271
+ return _empty(data) ?
14272
+ data :
14273
+ typeof data === 'string' ?
14274
+ data
14275
+ .replace( _re_new_lines, " " )
14276
+ .replace( _re_html, "" ) :
14277
+ '';
14278
+ },
14279
+
14280
+ string: function ( data ) {
14281
+ return _empty(data) ?
14282
+ data :
14283
+ typeof data === 'string' ?
14284
+ data.replace( _re_new_lines, " " ) :
14285
+ data;
14286
+ }
14287
+ } );
14288
+
14289
+
14290
+
13772
14291
  var __numericReplace = function ( d, decimalPlace, re1, re2 ) {
13773
- if ( !d || d === '-' ) {
14292
+ if ( d !== 0 && (!d || d === '-') ) {
13774
14293
  return -Infinity;
13775
14294
  }
13776
14295
 
@@ -13795,8 +14314,8 @@
13795
14314
  };
13796
14315
 
13797
14316
 
13798
- // Add the numeric 'deformatting' functions for sorting. This is done in a
13799
- // function to provide an easy ability for the language options to add
14317
+ // Add the numeric 'deformatting' functions for sorting and search. This is done
14318
+ // in a function to provide an easy ability for the language options to add
13800
14319
  // additional methods if a non-period decimal place is used.
13801
14320
  function _addNumericSort ( decimalPlace ) {
13802
14321
  $.each(
@@ -13822,7 +14341,13 @@
13822
14341
  }
13823
14342
  },
13824
14343
  function ( key, fn ) {
14344
+ // Add the ordering method
13825
14345
  _ext.type.order[ key+decimalPlace+'-pre' ] = fn;
14346
+
14347
+ // For HTML types add a search formatter that will strip the HTML
14348
+ if ( key.match(/^html\-/) ) {
14349
+ _ext.type.search[ key+decimalPlace ] = _ext.type.search.html;
14350
+ }
13826
14351
  }
13827
14352
  );
13828
14353
  }
@@ -13837,7 +14362,7 @@
13837
14362
 
13838
14363
  // html
13839
14364
  "html-pre": function ( a ) {
13840
- return ! a ?
14365
+ return _empty(a) ?
13841
14366
  '' :
13842
14367
  a.replace ?
13843
14368
  a.replace( /<.*?>/g, "" ).toLowerCase() :
@@ -13846,11 +14371,15 @@
13846
14371
 
13847
14372
  // string
13848
14373
  "string-pre": function ( a ) {
13849
- return typeof a === 'string' ?
13850
- a.toLowerCase() :
13851
- ! a || ! a.toString ?
13852
- '' :
13853
- a.toString();
14374
+ // This is a little complex, but faster than always calling toString,
14375
+ // http://jsperf.com/tostring-v-check
14376
+ return _empty(a) ?
14377
+ '' :
14378
+ typeof a === 'string' ?
14379
+ a.toLowerCase() :
14380
+ ! a.toString ?
14381
+ '' :
14382
+ a.toString();
13854
14383
  },
13855
14384
 
13856
14385
  // string-asc and -desc are retained only for compatibility with the old
@@ -13869,87 +14398,6 @@
13869
14398
  _addNumericSort( '' );
13870
14399
 
13871
14400
 
13872
- // Built in type detection. See model.ext.aTypes for information about
13873
- // what is required from this methods.
13874
- $.extend( DataTable.ext.type.detect, [
13875
- // Plain numbers - first since V8 detects some plain numbers as dates
13876
- // e.g. Date.parse('55') (but not all, e.g. Date.parse('22')...).
13877
- function ( d, settings )
13878
- {
13879
- var decimal = settings.oLanguage.sDecimal;
13880
- return _isNumber( d, decimal ) ? 'num'+decimal : null;
13881
- },
13882
-
13883
- // Dates (only those recognised by the browser's Date.parse)
13884
- function ( d, settings )
13885
- {
13886
- // V8 will remove any unknown characters at the start of the expression,
13887
- // leading to false matches such as `$245.12` being a valid date. See
13888
- // forum thread 18941 for detail.
13889
- if ( d && ! _re_date_start.test(d) ) {
13890
- return null;
13891
- }
13892
- var parsed = Date.parse(d);
13893
- return (parsed !== null && !isNaN(parsed)) || _empty(d) ? 'date' : null;
13894
- },
13895
-
13896
- // Formatted numbers
13897
- function ( d, settings )
13898
- {
13899
- var decimal = settings.oLanguage.sDecimal;
13900
- return _isNumber( d, decimal, true ) ? 'num-fmt'+decimal : null;
13901
- },
13902
-
13903
- // HTML numeric
13904
- function ( d, settings )
13905
- {
13906
- var decimal = settings.oLanguage.sDecimal;
13907
- return _htmlNumeric( d, decimal ) ? 'html-num'+decimal : null;
13908
- },
13909
-
13910
- // HTML numeric, formatted
13911
- function ( d, settings )
13912
- {
13913
- var decimal = settings.oLanguage.sDecimal;
13914
- return _htmlNumeric( d, decimal, true ) ? 'html-num-fmt'+decimal : null;
13915
- },
13916
-
13917
- // HTML (this is strict checking - there must be html)
13918
- function ( d, settings )
13919
- {
13920
- return _empty( d ) || (typeof d === 'string' && d.indexOf('<') !== -1) ?
13921
- 'html' : null;
13922
- }
13923
- ] );
13924
-
13925
-
13926
-
13927
- // Filter formatting functions. See model.ext.ofnSearch for information about
13928
- // what is required from these methods.
13929
-
13930
-
13931
- $.extend( DataTable.ext.type.search, {
13932
- html: function ( data ) {
13933
- return _empty(data) ?
13934
- '' :
13935
- typeof data === 'string' ?
13936
- data
13937
- .replace( _re_new_lines, " " )
13938
- .replace( _re_html, "" ) :
13939
- '';
13940
- },
13941
-
13942
- string: function ( data ) {
13943
- return _empty(data) ?
13944
- '' :
13945
- typeof data === 'string' ?
13946
- data.replace( _re_new_lines, " " ) :
13947
- data;
13948
- }
13949
- } );
13950
-
13951
-
13952
-
13953
14401
  $.extend( true, DataTable.ext.renderer, {
13954
14402
  header: {
13955
14403
  _: function ( settings, cell, column, classes ) {
@@ -13958,7 +14406,11 @@
13958
14406
  // `DT` namespace will allow the event to be removed automatically
13959
14407
  // on destroy, while the `dt` namespaced event is the one we are
13960
14408
  // listening for
13961
- $(settings.nTable).on( 'order.dt.DT', function ( e, settings, sorting, columns ) {
14409
+ $(settings.nTable).on( 'order.dt.DT', function ( e, ctx, sorting, columns ) {
14410
+ if ( settings !== ctx ) { // need to check this this is the host
14411
+ return; // table, not a nested one
14412
+ }
14413
+
13962
14414
  var colIdx = column.idx;
13963
14415
 
13964
14416
  cell
@@ -13976,8 +14428,6 @@
13976
14428
  },
13977
14429
 
13978
14430
  jqueryui: function ( settings, cell, column, classes ) {
13979
- var colIdx = column.idx;
13980
-
13981
14431
  $('<div/>')
13982
14432
  .addClass( classes.sSortJUIWrapper )
13983
14433
  .append( cell.contents() )
@@ -13987,7 +14437,13 @@
13987
14437
  .appendTo( cell );
13988
14438
 
13989
14439
  // Attach a sort listener to update on sort
13990
- $(settings.nTable).on( 'order.dt.DT', function ( e, settings, sorting, columns ) {
14440
+ $(settings.nTable).on( 'order.dt.DT', function ( e, ctx, sorting, columns ) {
14441
+ if ( settings !== ctx ) {
14442
+ return;
14443
+ }
14444
+
14445
+ var colIdx = column.idx;
14446
+
13991
14447
  cell
13992
14448
  .removeClass( classes.sSortAsc +" "+classes.sSortDesc )
13993
14449
  .addClass( columns[ colIdx ] == 'asc' ?
@@ -14049,13 +14505,15 @@
14049
14505
  number: function ( thousands, decimal, precision, prefix ) {
14050
14506
  return {
14051
14507
  display: function ( d ) {
14052
- d = parseFloat( d );
14508
+ var negative = d < 0 ? '-' : '';
14509
+ d = Math.abs( parseFloat( d ) );
14510
+
14053
14511
  var intPart = parseInt( d, 10 );
14054
14512
  var floatPart = precision ?
14055
- (decimal+(d - intPart).toFixed( precision )).substring( 2 ):
14513
+ decimal+(d - intPart).toFixed( precision ).substring( 2 ):
14056
14514
  '';
14057
14515
 
14058
- return (prefix||'') +
14516
+ return negative + (prefix||'') +
14059
14517
  intPart.toString().replace(
14060
14518
  /\B(?=(\d{3})+(?!\d))/g, thousands
14061
14519
  ) +
@@ -14128,7 +14586,7 @@
14128
14586
  _fnGetDataMaster: _fnGetDataMaster,
14129
14587
  _fnClearTable: _fnClearTable,
14130
14588
  _fnDeleteIndex: _fnDeleteIndex,
14131
- _fnInvalidateRow: _fnInvalidateRow,
14589
+ _fnInvalidate: _fnInvalidate,
14132
14590
  _fnGetRowElements: _fnGetRowElements,
14133
14591
  _fnCreateTr: _fnCreateTr,
14134
14592
  _fnBuildHead: _fnBuildHead,