lanes 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (391) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +19 -0
  3. data/.jshintrc +3 -0
  4. data/Gemfile +9 -0
  5. data/Guardfile +15 -0
  6. data/LICENSE-MIT.txt +21 -0
  7. data/README.md +15 -0
  8. data/Rakefile +74 -0
  9. data/bin/lanes +5 -0
  10. data/client/images/ajax-loader.gif +0 -0
  11. data/client/images/dataTables/Sorting icons.psd +0 -0
  12. data/client/images/dataTables/back_disabled.png +0 -0
  13. data/client/images/dataTables/back_enabled.png +0 -0
  14. data/client/images/dataTables/back_enabled_hover.png +0 -0
  15. data/client/images/dataTables/favicon.ico +0 -0
  16. data/client/images/dataTables/forward_disabled.png +0 -0
  17. data/client/images/dataTables/forward_enabled.png +0 -0
  18. data/client/images/dataTables/forward_enabled_hover.png +0 -0
  19. data/client/images/dataTables/loading-background.png +0 -0
  20. data/client/images/dataTables/sort_asc.png +0 -0
  21. data/client/images/dataTables/sort_asc_disabled.png +0 -0
  22. data/client/images/dataTables/sort_both.png +0 -0
  23. data/client/images/dataTables/sort_desc.png +0 -0
  24. data/client/images/dataTables/sort_desc_disabled.png +0 -0
  25. data/client/images/logo-sm.png +0 -0
  26. data/client/javascripts/component/Base.coffee +39 -0
  27. data/client/javascripts/component/ChoicesInput.coffee +47 -0
  28. data/client/javascripts/component/Grid.coffee +199 -0
  29. data/client/javascripts/component/ModalDialog.coffee +44 -0
  30. data/client/javascripts/component/PopOver.coffee +52 -0
  31. data/client/javascripts/component/RadioGroup.coffee +59 -0
  32. data/client/javascripts/component/RecordFinder.coffee +143 -0
  33. data/client/javascripts/component/SelectField.coffee +43 -0
  34. data/client/javascripts/component/TaggedField.coffee +27 -0
  35. data/client/javascripts/component/grid/Editor.coffee +65 -0
  36. data/client/javascripts/component/grid/PopOverEditor.coffee +29 -0
  37. data/client/javascripts/component/grid/RowEditor.coffee +31 -0
  38. data/client/javascripts/component/grid/popover-editor.html +18 -0
  39. data/client/javascripts/component/grid/row-editor.html +16 -0
  40. data/client/javascripts/component/grid.html +4 -0
  41. data/client/javascripts/component/index.js +5 -0
  42. data/client/javascripts/component/modal.html +17 -0
  43. data/client/javascripts/component/popover.html +5 -0
  44. data/client/javascripts/component/record-finder/clause.skr +35 -0
  45. data/client/javascripts/component/record-finder/dialog.skr +4 -0
  46. data/client/javascripts/component/record-finder/field.skr +8 -0
  47. data/client/javascripts/data/Bootstrap.coffee +8 -0
  48. data/client/javascripts/data/ChangeSet.coffee +50 -0
  49. data/client/javascripts/data/Collection.coffee +111 -0
  50. data/client/javascripts/data/Config.coffee +15 -0
  51. data/client/javascripts/data/Model.coffee +269 -0
  52. data/client/javascripts/data/PubSub.coffee +68 -0
  53. data/client/javascripts/data/Query.coffee +184 -0
  54. data/client/javascripts/data/Roles.coffee +91 -0
  55. data/client/javascripts/data/Screens.coffee +157 -0
  56. data/client/javascripts/data/Sync.coffee +62 -0
  57. data/client/javascripts/data/User.coffee +70 -0
  58. data/client/javascripts/data/index.js +7 -0
  59. data/client/javascripts/data/mixins/HasCodeField.coffee +13 -0
  60. data/client/javascripts/extension/Base.coffee +9 -0
  61. data/client/javascripts/extension/Extensions.coffee +17 -0
  62. data/client/javascripts/extension/GlAccounts.coffee +9 -0
  63. data/client/javascripts/extension/index.js +6 -0
  64. data/client/javascripts/extension/load.js.erb +3 -0
  65. data/client/javascripts/lanes-complete.js +3 -0
  66. data/client/javascripts/lanes-workspace.js +1 -0
  67. data/client/javascripts/lib/MakeBaseClass.coffee +55 -0
  68. data/client/javascripts/lib/ModuleSupport.coffee +22 -0
  69. data/client/javascripts/lib/Templates.coffee +47 -0
  70. data/client/javascripts/lib/create-namespace.js +0 -0
  71. data/client/javascripts/lib/debounce.coffee +15 -0
  72. data/client/javascripts/lib/defer.coffee +7 -0
  73. data/client/javascripts/lib/el.js +115 -0
  74. data/client/javascripts/lib/index.js +9 -0
  75. data/client/javascripts/lib/loader.coffee +95 -0
  76. data/client/javascripts/lib/namespace.coffee +9 -0
  77. data/client/javascripts/lib/noConflict.coffee +14 -0
  78. data/client/javascripts/lib/promise_helpers.coffee +4 -0
  79. data/client/javascripts/lib/results.coffee +15 -0
  80. data/client/javascripts/lib/underscore.inflection.js +210 -0
  81. data/client/javascripts/lib/utilFunctions.coffee +51 -0
  82. data/client/javascripts/plugins/ResizeSensor.js +144 -0
  83. data/client/javascripts/plugins/index.js +4 -0
  84. data/client/javascripts/plugins/overlay.coffee +41 -0
  85. data/client/javascripts/plugins/trigger.coffee +15 -0
  86. data/client/javascripts/vendor/bootstrap/affix.js +142 -0
  87. data/client/javascripts/vendor/bootstrap/alert.js +92 -0
  88. data/client/javascripts/vendor/bootstrap/button.js +110 -0
  89. data/client/javascripts/vendor/bootstrap/carousel.js +223 -0
  90. data/client/javascripts/vendor/bootstrap/collapse.js +170 -0
  91. data/client/javascripts/vendor/bootstrap/dropdown.js +151 -0
  92. data/client/javascripts/vendor/bootstrap/modal.js +280 -0
  93. data/client/javascripts/vendor/bootstrap/popover.js +113 -0
  94. data/client/javascripts/vendor/bootstrap/scrollspy.js +170 -0
  95. data/client/javascripts/vendor/bootstrap/tab.js +128 -0
  96. data/client/javascripts/vendor/bootstrap/tooltip.js +457 -0
  97. data/client/javascripts/vendor/bootstrap/transition.js +59 -0
  98. data/client/javascripts/vendor/dataTables/dataTables.bootstrap.js +156 -0
  99. data/client/javascripts/vendor/dataTables/dataTables.scroller.js +1185 -0
  100. data/client/javascripts/vendor/dataTables/datatables.responsive.js +666 -0
  101. data/client/javascripts/vendor/dataTables/index.js +2 -0
  102. data/client/javascripts/vendor/dataTables/jquery.dataTables.js +14380 -0
  103. data/client/javascripts/vendor/jquery-2.js +9190 -0
  104. data/client/javascripts/vendor/jquery.tap.js +401 -0
  105. data/client/javascripts/vendor/magicsuggest.js +1565 -0
  106. data/client/javascripts/vendor/message-bus.js +285 -0
  107. data/client/javascripts/vendor/modern-stack.js +14 -0
  108. data/client/javascripts/vendor/packaged.js +13769 -0
  109. data/client/javascripts/view/Assets.coffee +9 -0
  110. data/client/javascripts/view/Base.coffee +231 -0
  111. data/client/javascripts/view/FormBindings.coffee +98 -0
  112. data/client/javascripts/view/Functions.coffee +13 -0
  113. data/client/javascripts/view/Helpers.coffee +77 -0
  114. data/client/javascripts/view/InterfaceState.coffee +88 -0
  115. data/client/javascripts/view/Keys.coffee +59 -0
  116. data/client/javascripts/view/ModelObserver.coffee +31 -0
  117. data/client/javascripts/view/ModelUpdate.coffee +8 -0
  118. data/client/javascripts/view/PubSub.coffee +29 -0
  119. data/client/javascripts/view/RenderContext.coffee +32 -0
  120. data/client/javascripts/view/SaveNotify.coffee +30 -0
  121. data/client/javascripts/view/Screen.coffee +30 -0
  122. data/client/javascripts/view/TimedHighlight.coffee +38 -0
  123. data/client/javascripts/view/TimedMask.coffee +65 -0
  124. data/client/javascripts/view/_button.html +3 -0
  125. data/client/javascripts/view/_toolbar.html +27 -0
  126. data/client/javascripts/view/index.js +10 -0
  127. data/client/javascripts/view/mixins/ScreenChangeListener.coffee +43 -0
  128. data/client/javascripts/view/model-update.html +13 -0
  129. data/client/javascripts/view/screen-definitions.js.erb +7 -0
  130. data/client/javascripts/workspace/ActiveScreensSwitcher.coffee +117 -0
  131. data/client/javascripts/workspace/Instance.es6 +60 -0
  132. data/client/javascripts/workspace/Layout.coffee +18 -0
  133. data/client/javascripts/workspace/LoginDialog.coffee +33 -0
  134. data/client/javascripts/workspace/Navbar.coffee +44 -0
  135. data/client/javascripts/workspace/Pages.coffee +46 -0
  136. data/client/javascripts/workspace/ScreensMenu.coffee +126 -0
  137. data/client/javascripts/workspace/index.js +12 -0
  138. data/client/javascripts/workspace/layout.html +4 -0
  139. data/client/javascripts/workspace/login-dialog.html +16 -0
  140. data/client/javascripts/workspace/menu.html +356 -0
  141. data/client/javascripts/workspace/menu_toggle.html +9 -0
  142. data/client/javascripts/workspace/navbar.html +19 -0
  143. data/client/javascripts/workspace/pages.html +6 -0
  144. data/client/javascripts/workspace/screens-menu.html +11 -0
  145. data/client/javascripts/workspace/screens-switcher.html +7 -0
  146. data/client/javascripts/workspace/tab.html +0 -0
  147. data/client/screens/user-management/UserEditScreen.coffee +21 -0
  148. data/client/screens/user-management/UserManagement.coffee +24 -0
  149. data/client/screens/user-management/grid-popover-editor.html +33 -0
  150. data/client/screens/user-management/index.css +4 -0
  151. data/client/screens/user-management/index.js +2 -0
  152. data/client/screens/user-management/user-management-styles.scss +7 -0
  153. data/client/screens/user-management/user-management.html +8 -0
  154. data/client/stylesheets/compoonents/all.scss +6 -0
  155. data/client/stylesheets/compoonents/changes-notification.scss +44 -0
  156. data/client/stylesheets/compoonents/grid-editors.scss +65 -0
  157. data/client/stylesheets/compoonents/grid.scss +301 -0
  158. data/client/stylesheets/compoonents/modal-dialog.scss +23 -0
  159. data/client/stylesheets/compoonents/record-finder.scss +71 -0
  160. data/client/stylesheets/compoonents/suggest.scss +266 -0
  161. data/client/stylesheets/fonts/icomoon.eot +0 -0
  162. data/client/stylesheets/fonts/icomoon.svg +160 -0
  163. data/client/stylesheets/fonts/icomoon.ttf +0 -0
  164. data/client/stylesheets/fonts/icomoon.woff +0 -0
  165. data/client/stylesheets/fonts/selection.json +3565 -0
  166. data/client/stylesheets/fonts/style.css +451 -0
  167. data/client/stylesheets/fonts.scss +38 -0
  168. data/client/stylesheets/forms.scss +75 -0
  169. data/client/stylesheets/index.css +4 -0
  170. data/client/stylesheets/keybindings.scss +6 -0
  171. data/client/stylesheets/lanes-workspace.scss +17 -0
  172. data/client/stylesheets/layout.scss +272 -0
  173. data/client/stylesheets/plugins/all.scss +2 -0
  174. data/client/stylesheets/plugins/overlay.scss +63 -0
  175. data/client/stylesheets/plugins/resize-sensor.scss +24 -0
  176. data/client/stylesheets/screens.scss +66 -0
  177. data/client/stylesheets/tabs.scss +148 -0
  178. data/client/stylesheets/vendor/bootstrap/_alerts.scss +68 -0
  179. data/client/stylesheets/vendor/bootstrap/_badges.scss +57 -0
  180. data/client/stylesheets/vendor/bootstrap/_breadcrumbs.scss +26 -0
  181. data/client/stylesheets/vendor/bootstrap/_button-groups.scss +240 -0
  182. data/client/stylesheets/vendor/bootstrap/_buttons.scss +157 -0
  183. data/client/stylesheets/vendor/bootstrap/_carousel.scss +243 -0
  184. data/client/stylesheets/vendor/bootstrap/_close.scss +35 -0
  185. data/client/stylesheets/vendor/bootstrap/_code.scss +68 -0
  186. data/client/stylesheets/vendor/bootstrap/_component-animations.scss +35 -0
  187. data/client/stylesheets/vendor/bootstrap/_dropdowns.scss +215 -0
  188. data/client/stylesheets/vendor/bootstrap/_forms.scss +538 -0
  189. data/client/stylesheets/vendor/bootstrap/_glyphicons.scss +237 -0
  190. data/client/stylesheets/vendor/bootstrap/_grid.scss +84 -0
  191. data/client/stylesheets/vendor/bootstrap/_input-groups.scss +166 -0
  192. data/client/stylesheets/vendor/bootstrap/_jumbotron.scss +48 -0
  193. data/client/stylesheets/vendor/bootstrap/_labels.scss +66 -0
  194. data/client/stylesheets/vendor/bootstrap/_list-group.scss +132 -0
  195. data/client/stylesheets/vendor/bootstrap/_media.scss +56 -0
  196. data/client/stylesheets/vendor/bootstrap/_mixins.scss +39 -0
  197. data/client/stylesheets/vendor/bootstrap/_modals.scss +150 -0
  198. data/client/stylesheets/vendor/bootstrap/_navbar.scss +659 -0
  199. data/client/stylesheets/vendor/bootstrap/_navs.scss +242 -0
  200. data/client/stylesheets/vendor/bootstrap/_normalize.scss +425 -0
  201. data/client/stylesheets/vendor/bootstrap/_pager.scss +55 -0
  202. data/client/stylesheets/vendor/bootstrap/_pagination.scss +88 -0
  203. data/client/stylesheets/vendor/bootstrap/_panels.scss +243 -0
  204. data/client/stylesheets/vendor/bootstrap/_popovers.scss +133 -0
  205. data/client/stylesheets/vendor/bootstrap/_print.scss +101 -0
  206. data/client/stylesheets/vendor/bootstrap/_progress-bars.scss +105 -0
  207. data/client/stylesheets/vendor/bootstrap/_responsive-embed.scss +34 -0
  208. data/client/stylesheets/vendor/bootstrap/_responsive-utilities.scss +174 -0
  209. data/client/stylesheets/vendor/bootstrap/_scaffolding.scss +150 -0
  210. data/client/stylesheets/vendor/bootstrap/_tables.scss +233 -0
  211. data/client/stylesheets/vendor/bootstrap/_theme.scss +258 -0
  212. data/client/stylesheets/vendor/bootstrap/_thumbnails.scss +38 -0
  213. data/client/stylesheets/vendor/bootstrap/_tooltip.scss +95 -0
  214. data/client/stylesheets/vendor/bootstrap/_type.scss +304 -0
  215. data/client/stylesheets/vendor/bootstrap/_utilities.scss +57 -0
  216. data/client/stylesheets/vendor/bootstrap/_variables.scss +850 -0
  217. data/client/stylesheets/vendor/bootstrap/_wells.scss +29 -0
  218. data/client/stylesheets/vendor/bootstrap/bootstrap.scss +50 -0
  219. data/client/stylesheets/vendor/bootstrap/mixins/_alerts.scss +14 -0
  220. data/client/stylesheets/vendor/bootstrap/mixins/_background-variant.scss +11 -0
  221. data/client/stylesheets/vendor/bootstrap/mixins/_border-radius.scss +18 -0
  222. data/client/stylesheets/vendor/bootstrap/mixins/_buttons.scss +50 -0
  223. data/client/stylesheets/vendor/bootstrap/mixins/_center-block.scss +7 -0
  224. data/client/stylesheets/vendor/bootstrap/mixins/_clearfix.scss +22 -0
  225. data/client/stylesheets/vendor/bootstrap/mixins/_forms.scss +84 -0
  226. data/client/stylesheets/vendor/bootstrap/mixins/_gradients.scss +58 -0
  227. data/client/stylesheets/vendor/bootstrap/mixins/_grid-framework.scss +81 -0
  228. data/client/stylesheets/vendor/bootstrap/mixins/_grid.scss +122 -0
  229. data/client/stylesheets/vendor/bootstrap/mixins/_hide-text.scss +21 -0
  230. data/client/stylesheets/vendor/bootstrap/mixins/_image.scss +34 -0
  231. data/client/stylesheets/vendor/bootstrap/mixins/_labels.scss +12 -0
  232. data/client/stylesheets/vendor/bootstrap/mixins/_list-group.scss +31 -0
  233. data/client/stylesheets/vendor/bootstrap/mixins/_nav-divider.scss +10 -0
  234. data/client/stylesheets/vendor/bootstrap/mixins/_nav-vertical-align.scss +9 -0
  235. data/client/stylesheets/vendor/bootstrap/mixins/_opacity.scss +8 -0
  236. data/client/stylesheets/vendor/bootstrap/mixins/_pagination.scss +23 -0
  237. data/client/stylesheets/vendor/bootstrap/mixins/_panels.scss +24 -0
  238. data/client/stylesheets/vendor/bootstrap/mixins/_progress-bar.scss +10 -0
  239. data/client/stylesheets/vendor/bootstrap/mixins/_reset-filter.scss +8 -0
  240. data/client/stylesheets/vendor/bootstrap/mixins/_resize.scss +6 -0
  241. data/client/stylesheets/vendor/bootstrap/mixins/_responsive-visibility.scss +21 -0
  242. data/client/stylesheets/vendor/bootstrap/mixins/_size.scss +10 -0
  243. data/client/stylesheets/vendor/bootstrap/mixins/_tab-focus.scss +9 -0
  244. data/client/stylesheets/vendor/bootstrap/mixins/_table-row.scss +28 -0
  245. data/client/stylesheets/vendor/bootstrap/mixins/_text-emphasis.scss +11 -0
  246. data/client/stylesheets/vendor/bootstrap/mixins/_text-overflow.scss +8 -0
  247. data/client/stylesheets/vendor/bootstrap/mixins/_vendor-prefixes.scss +219 -0
  248. data/client/stylesheets/vendor/bootstrap-custom-grid.scss +85 -0
  249. data/client/stylesheets/vendor/bootstrap-custom-modals.scss +150 -0
  250. data/client/stylesheets/vendor/bootstrap.scss +69 -0
  251. data/client/stylesheets/vendor/dataTables.scss +4 -0
  252. data/config/database.yml +9 -0
  253. data/config/puma.rb +7 -0
  254. data/config.ru +4 -0
  255. data/db/migrate/20140615031600_create_hip_users.rb +17 -0
  256. data/db/seed.rb +37 -0
  257. data/foo/Gemfile +5 -0
  258. data/foo/Guardfile +13 -0
  259. data/foo/foo/Gemfile +5 -0
  260. data/foo/foo/lib/foo.rb +7 -0
  261. data/foo/lib/foo/version.rb +3 -0
  262. data/foo/lib/foo.rb +8 -0
  263. data/lanes.gemspec +54 -0
  264. data/lib/generators/lanes/migrations/install_generator.rb +42 -0
  265. data/lib/lanes/access/locked_fields.rb +43 -0
  266. data/lib/lanes/access/role.rb +58 -0
  267. data/lib/lanes/access/role_collection.rb +75 -0
  268. data/lib/lanes/access/roles/administrator.rb +25 -0
  269. data/lib/lanes/access/roles/support.rb +13 -0
  270. data/lib/lanes/access/user_maint_screen.rb +32 -0
  271. data/lib/lanes/access.rb +50 -0
  272. data/lib/lanes/api/asset_pipeline.rb +59 -0
  273. data/lib/lanes/api/authentication_helper.rb +21 -0
  274. data/lib/lanes/api/authentication_provider.rb +45 -0
  275. data/lib/lanes/api/controller.rb +290 -0
  276. data/lib/lanes/api/default_routes.rb +35 -0
  277. data/lib/lanes/api/eco.js +516 -0
  278. data/lib/lanes/api/error_formatter.rb +37 -0
  279. data/lib/lanes/api/helper_methods.rb +32 -0
  280. data/lib/lanes/api/javascript_processor.rb +116 -0
  281. data/lib/lanes/api/pub_sub.rb +33 -0
  282. data/lib/lanes/api/request_wrapper.rb +42 -0
  283. data/lib/lanes/api/root.rb +103 -0
  284. data/lib/lanes/api/skr_templates.rb +60 -0
  285. data/lib/lanes/api/test_specs.rb +59 -0
  286. data/lib/lanes/api/updates.rb +38 -0
  287. data/lib/lanes/api.rb +27 -0
  288. data/lib/lanes/cli.rb +13 -0
  289. data/lib/lanes/concerns/all.rb +16 -0
  290. data/lib/lanes/concerns/api_path.rb +21 -0
  291. data/lib/lanes/concerns/association_extensions.rb +85 -0
  292. data/lib/lanes/concerns/attr_accessor_with_default.rb +62 -0
  293. data/lib/lanes/concerns/code_identifier.rb +43 -0
  294. data/lib/lanes/concerns/export_associations.rb +52 -0
  295. data/lib/lanes/concerns/export_join_tables.rb +39 -0
  296. data/lib/lanes/concerns/export_methods.rb +104 -0
  297. data/lib/lanes/concerns/export_scope.rb +66 -0
  298. data/lib/lanes/concerns/exported_limit_evaluator.rb +17 -0
  299. data/lib/lanes/concerns/immutable_model.rb +32 -0
  300. data/lib/lanes/concerns/locked_fields.rb +84 -0
  301. data/lib/lanes/concerns/pub_sub.rb +105 -0
  302. data/lib/lanes/concerns/queries.rb +20 -0
  303. data/lib/lanes/concerns/random_hash_code.rb +40 -0
  304. data/lib/lanes/concerns/sanitize_api_data.rb +15 -0
  305. data/lib/lanes/concerns/set_attribute_data.rb +154 -0
  306. data/lib/lanes/concerns/track_modifications.rb +51 -0
  307. data/lib/lanes/concerns/visible_id_identifier.rb +53 -0
  308. data/lib/lanes/configuration.rb +85 -0
  309. data/lib/lanes/db/migration_helpers.rb +178 -0
  310. data/lib/lanes/db/migrations.rb +13 -0
  311. data/lib/lanes/db/seed.rb +27 -0
  312. data/lib/lanes/db.rb +86 -0
  313. data/lib/lanes/environment.rb +19 -0
  314. data/lib/lanes/extension.rb +72 -0
  315. data/lib/lanes/generators/app/Gemfile +5 -0
  316. data/lib/lanes/generators/app/Guardfile +13 -0
  317. data/lib/lanes/generators/app/Rakefile +9 -0
  318. data/lib/lanes/generators/app/config/database.yml +9 -0
  319. data/lib/lanes/generators/app/config.ru +4 -0
  320. data/lib/lanes/generators/app/lib/main_class/version.rb +3 -0
  321. data/lib/lanes/generators/app/lib/main_class.rb +8 -0
  322. data/lib/lanes/generators/app.rb +36 -0
  323. data/lib/lanes/guard_tasks.rb +44 -0
  324. data/lib/lanes/logger.rb +37 -0
  325. data/lib/lanes/model.rb +26 -0
  326. data/lib/lanes/numbers.rb +72 -0
  327. data/lib/lanes/rails_engine.rb +5 -0
  328. data/lib/lanes/screens.rb +126 -0
  329. data/lib/lanes/spec_asset_expander.rb +43 -0
  330. data/lib/lanes/strings.rb +56 -0
  331. data/lib/lanes/user.rb +127 -0
  332. data/lib/lanes/validators/all.rb +2 -0
  333. data/lib/lanes/validators/email.rb +17 -0
  334. data/lib/lanes/validators/set.rb +18 -0
  335. data/lib/lanes/version.rb +5 -0
  336. data/lib/lanes.rb +22 -0
  337. data/npm-build/README +1 -0
  338. data/npm-build/compile.coffee +15 -0
  339. data/npm-build/package.json +59 -0
  340. data/npm-build/shims/underscore.js +1416 -0
  341. data/npm-build/template.js +33 -0
  342. data/public/javascripts/jasmine_examples/Player.js +22 -0
  343. data/public/javascripts/jasmine_examples/Song.js +7 -0
  344. data/spec/api/javascript_processor_spec.rb +107 -0
  345. data/spec/api/user_spec.rb +52 -0
  346. data/spec/client/component/ChoicesInputSpec.coffee +12 -0
  347. data/spec/client/component/foo_spec.coffee +4 -0
  348. data/spec/client/foo_spec.js +0 -0
  349. data/spec/client/jasmine_examples/PlayerSpec.js +0 -0
  350. data/spec/client/support/jasmine.yml +128 -0
  351. data/spec/client/support/jasmine_helper.rb +15 -0
  352. data/spec/concerns/api_path_spec.rb +14 -0
  353. data/spec/concerns/association_extensions_spec.rb +30 -0
  354. data/spec/concerns/attr_accessor_with_default_spec.rb +57 -0
  355. data/spec/concerns/code_identifier_spec.rb +45 -0
  356. data/spec/concerns/export_associations_spec.rb +7 -0
  357. data/spec/concerns/export_methods_spec.rb +43 -0
  358. data/spec/concerns/export_scope_spec.rb +15 -0
  359. data/spec/concerns/exported_limits_spec.rb +47 -0
  360. data/spec/concerns/pub_sub_spec.rb +83 -0
  361. data/spec/concerns/set_attribute_data_spec.rb +66 -0
  362. data/spec/configuration_spec.rb +26 -0
  363. data/spec/fixtures/lanes/users.yml +13 -0
  364. data/spec/helpers/.gitkeep +0 -0
  365. data/spec/helpers/SpecHelper.js +18 -0
  366. data/spec/locked_fields_spec.rb +27 -0
  367. data/spec/numbers_spec.rb +26 -0
  368. data/spec/role_collection_spec.rb +19 -0
  369. data/spec/spec_helper.rb +163 -0
  370. data/spec/strings_spec.rb +41 -0
  371. data/spec/testing_models.rb +54 -0
  372. data/spec/user_role_spec.rb +7 -0
  373. data/spec/user_spec.rb +53 -0
  374. data/tasks/migrations.rake +22 -0
  375. data/tasks/publish.rake +8 -0
  376. data/views/index.erb +29 -0
  377. data/views/specs.erb +25 -0
  378. data/yard_ext/all.rb +9 -0
  379. data/yard_ext/code_identifier_handler.rb +33 -0
  380. data/yard_ext/concern_meta_methods.rb +60 -0
  381. data/yard_ext/config_options.rb +27 -0
  382. data/yard_ext/exported_scope.rb +4 -0
  383. data/yard_ext/immutable_handler.rb +17 -0
  384. data/yard_ext/json_attr_accessor.rb +22 -0
  385. data/yard_ext/locked_fields_handler.rb +21 -0
  386. data/yard_ext/templates/default/layout/html/layout.erb +20 -0
  387. data/yard_ext/templates/default/method_details/html/github_link.erb +1 -0
  388. data/yard_ext/templates/default/method_details/setup.rb +3 -0
  389. data/yard_ext/validators.rb +1 -0
  390. data/yard_ext/visible_id_handler.rb +38 -0
  391. metadata +772 -0
@@ -0,0 +1,1185 @@
1
+ /*! Scroller 1.2.1
2
+ * 2011-2014 SpryMedia Ltd - datatables.net/license
3
+ */
4
+
5
+ /**
6
+ * @summary Scroller
7
+ * @description Virtual rendering for DataTables
8
+ * @version 1.2.1
9
+ * @file dataTables.scroller.js
10
+ * @author SpryMedia Ltd (www.sprymedia.co.uk)
11
+ * @contact www.sprymedia.co.uk/contact
12
+ * @copyright Copyright 2011-2014 SpryMedia Ltd.
13
+ *
14
+ * This source file is free software, available under the following license:
15
+ * MIT license - http://datatables.net/license/mit
16
+ *
17
+ * This source file is distributed in the hope that it will be useful, but
18
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
19
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
20
+ *
21
+ * For details please refer to: http://www.datatables.net
22
+ */
23
+
24
+ (function(window, document, undefined){
25
+
26
+
27
+ var factory = function( $, DataTable ) {
28
+ "use strict";
29
+
30
+ /**
31
+ * Scroller is a virtual rendering plug-in for DataTables which allows large
32
+ * datasets to be drawn on screen every quickly. What the virtual rendering means
33
+ * is that only the visible portion of the table (and a bit to either side to make
34
+ * the scrolling smooth) is drawn, while the scrolling container gives the
35
+ * visual impression that the whole table is visible. This is done by making use
36
+ * of the pagination abilities of DataTables and moving the table around in the
37
+ * scrolling container DataTables adds to the page. The scrolling container is
38
+ * forced to the height it would be for the full table display using an extra
39
+ * element.
40
+ *
41
+ * Note that rows in the table MUST all be the same height. Information in a cell
42
+ * which expands on to multiple lines will cause some odd behaviour in the scrolling.
43
+ *
44
+ * Scroller is initialised by simply including the letter 'S' in the sDom for the
45
+ * table you want to have this feature enabled on. Note that the 'S' must come
46
+ * AFTER the 't' parameter in `dom`.
47
+ *
48
+ * Key features include:
49
+ * <ul class="limit_length">
50
+ * <li>Speed! The aim of Scroller for DataTables is to make rendering large data sets fast</li>
51
+ * <li>Full compatibility with deferred rendering in DataTables 1.9 for maximum speed</li>
52
+ * <li>Display millions of rows</li>
53
+ * <li>Integration with state saving in DataTables (scrolling position is saved)</li>
54
+ * <li>Easy to use</li>
55
+ * </ul>
56
+ *
57
+ * @class
58
+ * @constructor
59
+ * @global
60
+ * @param {object} oDT DataTables settings object
61
+ * @param {object} [oOpts={}] Configuration object for FixedColumns. Options
62
+ * are defined by {@link Scroller.defaults}
63
+ *
64
+ * @requires jQuery 1.7+
65
+ * @requires DataTables 1.9.0+
66
+ *
67
+ * @example
68
+ * $(document).ready(function() {
69
+ * $('#example').dataTable( {
70
+ * "sScrollY": "200px",
71
+ * "sAjaxSource": "media/dataset/large.txt",
72
+ * "sDom": "frtiS",
73
+ * "bDeferRender": true
74
+ * } );
75
+ * } );
76
+ */
77
+ var Scroller = function ( oDTSettings, oOpts ) {
78
+ /* Sanity check - you just know it will happen */
79
+ if ( ! this instanceof Scroller )
80
+ {
81
+ alert( "Scroller warning: Scroller must be initialised with the 'new' keyword." );
82
+ return;
83
+ }
84
+
85
+ if ( typeof oOpts == 'undefined' )
86
+ {
87
+ oOpts = {};
88
+ }
89
+
90
+ /**
91
+ * Settings object which contains customisable information for the Scroller instance
92
+ * @namespace
93
+ * @private
94
+ * @extends Scroller.defaults
95
+ */
96
+ this.s = {
97
+ /**
98
+ * DataTables settings object
99
+ * @type object
100
+ * @default Passed in as first parameter to constructor
101
+ */
102
+ "dt": oDTSettings,
103
+
104
+ /**
105
+ * Pixel location of the top of the drawn table in the viewport
106
+ * @type int
107
+ * @default 0
108
+ */
109
+ "tableTop": 0,
110
+
111
+ /**
112
+ * Pixel location of the bottom of the drawn table in the viewport
113
+ * @type int
114
+ * @default 0
115
+ */
116
+ "tableBottom": 0,
117
+
118
+ /**
119
+ * Pixel location of the boundary for when the next data set should be loaded and drawn
120
+ * when scrolling up the way.
121
+ * @type int
122
+ * @default 0
123
+ * @private
124
+ */
125
+ "redrawTop": 0,
126
+
127
+ /**
128
+ * Pixel location of the boundary for when the next data set should be loaded and drawn
129
+ * when scrolling down the way. Note that this is actually caluated as the offset from
130
+ * the top.
131
+ * @type int
132
+ * @default 0
133
+ * @private
134
+ */
135
+ "redrawBottom": 0,
136
+
137
+ /**
138
+ * Auto row height or not indicator
139
+ * @type bool
140
+ * @default 0
141
+ */
142
+ "autoHeight": true,
143
+
144
+ /**
145
+ * Number of rows calculated as visible in the visible viewport
146
+ * @type int
147
+ * @default 0
148
+ */
149
+ "viewportRows": 0,
150
+
151
+ /**
152
+ * setTimeout reference for state saving, used when state saving is enabled in the DataTable
153
+ * and when the user scrolls the viewport in order to stop the cookie set taking too much
154
+ * CPU!
155
+ * @type int
156
+ * @default 0
157
+ */
158
+ "stateTO": null,
159
+
160
+ /**
161
+ * setTimeout reference for the redraw, used when server-side processing is enabled in the
162
+ * DataTables in order to prevent DoSing the server
163
+ * @type int
164
+ * @default null
165
+ */
166
+ "drawTO": null,
167
+
168
+ heights: {
169
+ jump: null,
170
+ page: null,
171
+ virtual: null,
172
+ scroll: null,
173
+
174
+ /**
175
+ * Height of rows in the table
176
+ * @type int
177
+ * @default 0
178
+ */
179
+ row: null,
180
+
181
+ /**
182
+ * Pixel height of the viewport
183
+ * @type int
184
+ * @default 0
185
+ */
186
+ viewport: null
187
+ },
188
+
189
+ topRowFloat: 0,
190
+ scrollDrawDiff: null
191
+ };
192
+
193
+ // @todo The defaults should extend a `c` property and the internal settings
194
+ // only held in the `s` property. At the moment they are mixed
195
+ this.s = $.extend( this.s, Scroller.oDefaults, oOpts );
196
+
197
+ // Workaround for row height being read from height object (see above comment)
198
+ this.s.heights.row = this.s.rowHeight;
199
+
200
+ /**
201
+ * DOM elements used by the class instance
202
+ * @private
203
+ * @namespace
204
+ *
205
+ */
206
+ this.dom = {
207
+ "force": document.createElement('div'),
208
+ "scroller": null,
209
+ "table": null
210
+ };
211
+
212
+ /* Attach the instance to the DataTables instance so it can be accessed */
213
+ this.s.dt.oScroller = this;
214
+
215
+ /* Let's do it */
216
+ this._fnConstruct();
217
+ };
218
+
219
+
220
+
221
+ Scroller.prototype = /** @lends Scroller.prototype */{
222
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
223
+ * Public methods
224
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
225
+
226
+ /**
227
+ * Calculate the pixel position from the top of the scrolling container for
228
+ * a given row
229
+ * @param {int} iRow Row number to calculate the position of
230
+ * @returns {int} Pixels
231
+ * @example
232
+ * $(document).ready(function() {
233
+ * $('#example').dataTable( {
234
+ * "sScrollY": "200px",
235
+ * "sAjaxSource": "media/dataset/large.txt",
236
+ * "sDom": "frtiS",
237
+ * "bDeferRender": true,
238
+ * "fnInitComplete": function (o) {
239
+ * // Find where row 25 is
240
+ * alert( o.oScroller.fnRowToPixels( 25 ) );
241
+ * }
242
+ * } );
243
+ * } );
244
+ */
245
+ "fnRowToPixels": function ( rowIdx, intParse, virtual )
246
+ {
247
+ var pixels;
248
+
249
+ if ( virtual ) {
250
+ pixels = this._domain( 'virtualToPhysical', rowIdx * this.s.heights.row );
251
+ }
252
+ else {
253
+ var diff = rowIdx - this.s.baseRowTop;
254
+ pixels = this.s.baseScrollTop + (diff * this.s.heights.row);
255
+ }
256
+
257
+ return intParse || intParse === undefined ?
258
+ parseInt( pixels, 10 ) :
259
+ pixels;
260
+ },
261
+
262
+
263
+ /**
264
+ * Calculate the row number that will be found at the given pixel position
265
+ * (y-scroll).
266
+ *
267
+ * Please note that when the height of the full table exceeds 1 million
268
+ * pixels, Scroller switches into a non-linear mode for the scrollbar to fit
269
+ * all of the records into a finite area, but this function returns a linear
270
+ * value (relative to the last non-linear positioning).
271
+ * @param {int} iPixels Offset from top to calculate the row number of
272
+ * @param {int} [intParse=true] If an integer value should be returned
273
+ * @param {int} [virtual=false] Perform the calculations in the virtual domain
274
+ * @returns {int} Row index
275
+ * @example
276
+ * $(document).ready(function() {
277
+ * $('#example').dataTable( {
278
+ * "sScrollY": "200px",
279
+ * "sAjaxSource": "media/dataset/large.txt",
280
+ * "sDom": "frtiS",
281
+ * "bDeferRender": true,
282
+ * "fnInitComplete": function (o) {
283
+ * // Find what row number is at 500px
284
+ * alert( o.oScroller.fnPixelsToRow( 500 ) );
285
+ * }
286
+ * } );
287
+ * } );
288
+ */
289
+ "fnPixelsToRow": function ( pixels, intParse, virtual )
290
+ {
291
+ var diff = pixels - this.s.baseScrollTop;
292
+ var row = virtual ?
293
+ this._domain( 'physicalToVirtual', pixels ) / this.s.heights.row :
294
+ ( diff / this.s.heights.row ) + this.s.baseRowTop;
295
+
296
+ return intParse || intParse === undefined ?
297
+ parseInt( row, 10 ) :
298
+ row;
299
+ },
300
+
301
+
302
+ /**
303
+ * Calculate the row number that will be found at the given pixel position (y-scroll)
304
+ * @param {int} iRow Row index to scroll to
305
+ * @param {bool} [bAnimate=true] Animate the transision or not
306
+ * @returns {void}
307
+ * @example
308
+ * $(document).ready(function() {
309
+ * $('#example').dataTable( {
310
+ * "sScrollY": "200px",
311
+ * "sAjaxSource": "media/dataset/large.txt",
312
+ * "sDom": "frtiS",
313
+ * "bDeferRender": true,
314
+ * "fnInitComplete": function (o) {
315
+ * // Immediately scroll to row 1000
316
+ * o.oScroller.fnScrollToRow( 1000 );
317
+ * }
318
+ * } );
319
+ *
320
+ * // Sometime later on use the following to scroll to row 500...
321
+ * var oSettings = $('#example').dataTable().fnSettings();
322
+ * oSettings.oScroller.fnScrollToRow( 500 );
323
+ * } );
324
+ */
325
+ "fnScrollToRow": function ( iRow, bAnimate )
326
+ {
327
+ var that = this;
328
+ var ani = false;
329
+ var px = this.fnRowToPixels( iRow );
330
+
331
+ // We need to know if the table will redraw or not before doing the
332
+ // scroll. If it will not redraw, then we need to use the currently
333
+ // displayed table, and scroll with the physical pixels. Otherwise, we
334
+ // need to calculate the table's new position from the virtual
335
+ // transform.
336
+ var preRows = ((this.s.displayBuffer-1)/2) * this.s.viewportRows;
337
+ var drawRow = iRow - preRows;
338
+ if ( drawRow < 0 ) {
339
+ drawRow = 0;
340
+ }
341
+
342
+ if ( (px > this.s.redrawBottom || px < this.s.redrawTop) && this.s.dt._iDisplayStart !== drawRow ) {
343
+ ani = true;
344
+ px = this.fnRowToPixels( iRow, false, true );
345
+ }
346
+
347
+ if ( typeof bAnimate == 'undefined' || bAnimate )
348
+ {
349
+ this.s.ani = ani;
350
+ $(this.dom.scroller).animate( {
351
+ "scrollTop": px
352
+ }, function () {
353
+ // This needs to happen after the animation has completed and
354
+ // the final scroll event fired
355
+ setTimeout( function () {
356
+ that.s.ani = false;
357
+ }, 0 );
358
+ } );
359
+ }
360
+ else
361
+ {
362
+ $(this.dom.scroller).scrollTop( px );
363
+ }
364
+ },
365
+
366
+
367
+ /**
368
+ * Calculate and store information about how many rows are to be displayed
369
+ * in the scrolling viewport, based on current dimensions in the browser's
370
+ * rendering. This can be particularly useful if the table is initially
371
+ * drawn in a hidden element - for example in a tab.
372
+ * @param {bool} [bRedraw=true] Redraw the table automatically after the recalculation, with
373
+ * the new dimentions forming the basis for the draw.
374
+ * @returns {void}
375
+ * @example
376
+ * $(document).ready(function() {
377
+ * // Make the example container hidden to throw off the browser's sizing
378
+ * document.getElementById('container').style.display = "none";
379
+ * var oTable = $('#example').dataTable( {
380
+ * "sScrollY": "200px",
381
+ * "sAjaxSource": "media/dataset/large.txt",
382
+ * "sDom": "frtiS",
383
+ * "bDeferRender": true,
384
+ * "fnInitComplete": function (o) {
385
+ * // Immediately scroll to row 1000
386
+ * o.oScroller.fnScrollToRow( 1000 );
387
+ * }
388
+ * } );
389
+ *
390
+ * setTimeout( function () {
391
+ * // Make the example container visible and recalculate the scroller sizes
392
+ * document.getElementById('container').style.display = "block";
393
+ * oTable.fnSettings().oScroller.fnMeasure();
394
+ * }, 3000 );
395
+ */
396
+ "fnMeasure": function ( bRedraw )
397
+ {
398
+ if ( this.s.autoHeight )
399
+ {
400
+ this._fnCalcRowHeight();
401
+ }
402
+
403
+ var heights = this.s.heights;
404
+
405
+ heights.viewport = $(this.dom.scroller).height();
406
+ this.s.viewportRows = parseInt( heights.viewport / heights.row, 10 )+1;
407
+ this.s.dt._iDisplayLength = this.s.viewportRows * this.s.displayBuffer;
408
+
409
+ if ( typeof bRedraw == 'undefined' || bRedraw )
410
+ {
411
+ this.s.dt.oInstance.fnDraw();
412
+ }
413
+ },
414
+
415
+
416
+
417
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
418
+ * Private methods (they are of course public in JS, but recommended as private)
419
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
420
+
421
+ /**
422
+ * Initialisation for Scroller
423
+ * @returns {void}
424
+ * @private
425
+ */
426
+ "_fnConstruct": function ()
427
+ {
428
+ var that = this;
429
+
430
+ /* Sanity check */
431
+ if ( !this.s.dt.oFeatures.bPaginate ) {
432
+ this.s.dt.oApi._fnLog( this.s.dt, 0, 'Pagination must be enabled for Scroller' );
433
+ return;
434
+ }
435
+
436
+ /* Insert a div element that we can use to force the DT scrolling container to
437
+ * the height that would be required if the whole table was being displayed
438
+ */
439
+ this.dom.force.style.position = "absolute";
440
+ this.dom.force.style.top = "0px";
441
+ this.dom.force.style.left = "0px";
442
+ this.dom.force.style.width = "1px";
443
+
444
+ this.dom.scroller = $('div.'+this.s.dt.oClasses.sScrollBody, this.s.dt.nTableWrapper)[0];
445
+ this.dom.scroller.appendChild( this.dom.force );
446
+ this.dom.scroller.style.position = "relative";
447
+
448
+ this.dom.table = $('>table', this.dom.scroller)[0];
449
+ this.dom.table.style.position = "absolute";
450
+ this.dom.table.style.top = "0px";
451
+ this.dom.table.style.left = "0px";
452
+
453
+ // Add class to 'announce' that we are a Scroller table
454
+ $(this.s.dt.nTableWrapper).addClass('DTS');
455
+
456
+ // Add a 'loading' indicator
457
+ if ( this.s.loadingIndicator )
458
+ {
459
+ $(this.dom.scroller.parentNode)
460
+ .css('position', 'relative')
461
+ .append('<div class="DTS_Loading">'+this.s.dt.oLanguage.sLoadingRecords+'</div>');
462
+ }
463
+
464
+ /* Initial size calculations */
465
+ if ( this.s.heights.row && this.s.heights.row != 'auto' )
466
+ {
467
+ this.s.autoHeight = false;
468
+ }
469
+ this.fnMeasure( false );
470
+
471
+ /* Scrolling callback to see if a page change is needed */
472
+ $(this.dom.scroller).on( 'scroll.DTS', function () {
473
+ that._fnScroll.call( that );
474
+ } );
475
+
476
+ /* In iOS we catch the touchstart event incase the user tries to scroll
477
+ * while the display is already scrolling
478
+ */
479
+ $(this.dom.scroller).on('touchstart.DTS', function () {
480
+ that._fnScroll.call( that );
481
+ } );
482
+
483
+ /* Update the scroller when the DataTable is redrawn */
484
+ this.s.dt.aoDrawCallback.push( {
485
+ "fn": function () {
486
+ if ( that.s.dt.bInitialised ) {
487
+ that._fnDrawCallback.call( that );
488
+ }
489
+ },
490
+ "sName": "Scroller"
491
+ } );
492
+
493
+ /* On resize, update the information element, since the number of rows shown might change */
494
+ $(window).on( 'resize.DTS', function () {
495
+ that._fnInfo();
496
+ } );
497
+
498
+ /* Add a state saving parameter to the DT state saving so we can restore the exact
499
+ * position of the scrolling
500
+ */
501
+ var initialStateSave = true;
502
+ this.s.dt.oApi._fnCallbackReg( this.s.dt, 'aoStateSaveParams', function (oS, oData) {
503
+ /* Set iScroller to saved scroll position on initialization.
504
+ */
505
+ if(initialStateSave && that.s.dt.oLoadedState){
506
+ oData.iScroller = that.s.dt.oLoadedState.iScroller;
507
+ initialStateSave = false;
508
+ } else {
509
+ oData.iScroller = that.dom.scroller.scrollTop;
510
+ }
511
+ }, "Scroller_State" );
512
+
513
+ /* Destructor */
514
+ this.s.dt.aoDestroyCallback.push( {
515
+ "sName": "Scroller",
516
+ "fn": function () {
517
+ $(window).off( 'resize.DTS' );
518
+ $(that.dom.scroller).off('touchstart.DTS scroll.DTS');
519
+ $(that.s.dt.nTableWrapper).removeClass('DTS');
520
+ $('div.DTS_Loading', that.dom.scroller.parentNode).remove();
521
+
522
+ that.dom.table.style.position = "";
523
+ that.dom.table.style.top = "";
524
+ that.dom.table.style.left = "";
525
+ }
526
+ } );
527
+ },
528
+
529
+
530
+ /**
531
+ * Scrolling function - fired whenever the scrolling position is changed.
532
+ * This method needs to use the stored values to see if the table should be
533
+ * redrawn as we are moving towards the end of the information that is
534
+ * currently drawn or not. If needed, then it will redraw the table based on
535
+ * the new position.
536
+ * @returns {void}
537
+ * @private
538
+ */
539
+ "_fnScroll": function ()
540
+ {
541
+ var
542
+ that = this,
543
+ heights = this.s.heights,
544
+ iScrollTop = this.dom.scroller.scrollTop,
545
+ iTopRow;
546
+
547
+ if ( this.s.skip ) {
548
+ return;
549
+ }
550
+
551
+ /* If the table has been sorted or filtered, then we use the redraw that
552
+ * DataTables as done, rather than performing our own
553
+ */
554
+ if ( this.s.dt.bFiltered || this.s.dt.bSorted ) {
555
+ this.s.lastScrollTop = 0;
556
+ return;
557
+ }
558
+
559
+ /* Update the table's information display for what is now in the viewport */
560
+ this._fnInfo();
561
+
562
+ /* We don't want to state save on every scroll event - that's heavy
563
+ * handed, so use a timeout to update the state saving only when the
564
+ * scrolling has finished
565
+ */
566
+ clearTimeout( this.s.stateTO );
567
+ this.s.stateTO = setTimeout( function () {
568
+ that.s.dt.oApi._fnSaveState( that.s.dt );
569
+ }, 250 );
570
+
571
+ /* Check if the scroll point is outside the trigger boundary which would required
572
+ * a DataTables redraw
573
+ */
574
+ if ( iScrollTop < this.s.redrawTop || iScrollTop > this.s.redrawBottom ) {
575
+ var preRows = Math.ceil( ((this.s.displayBuffer-1)/2) * this.s.viewportRows );
576
+
577
+ if ( Math.abs( iScrollTop - this.s.lastScrollTop ) > heights.viewport || this.s.ani ) {
578
+ iTopRow = parseInt(this._domain( 'physicalToVirtual', iScrollTop ) / heights.row, 10) - preRows;
579
+ this.s.topRowFloat = (this._domain( 'physicalToVirtual', iScrollTop ) / heights.row);
580
+ }
581
+ else {
582
+ iTopRow = this.fnPixelsToRow( iScrollTop ) - preRows;
583
+ this.s.topRowFloat = this.fnPixelsToRow( iScrollTop, false );
584
+ }
585
+
586
+ if ( iTopRow <= 0 ) {
587
+ /* At the start of the table */
588
+ iTopRow = 0;
589
+ }
590
+ else if ( iTopRow + this.s.dt._iDisplayLength > this.s.dt.fnRecordsDisplay() ) {
591
+ /* At the end of the table */
592
+ iTopRow = this.s.dt.fnRecordsDisplay() - this.s.dt._iDisplayLength;
593
+ if ( iTopRow < 0 ) {
594
+ iTopRow = 0;
595
+ }
596
+ }
597
+ else if ( iTopRow % 2 !== 0 ) {
598
+ // For the row-striping classes (odd/even) we want only to start
599
+ // on evens otherwise the stripes will change between draws and
600
+ // look rubbish
601
+ iTopRow++;
602
+ }
603
+
604
+ if ( iTopRow != this.s.dt._iDisplayStart ) {
605
+ /* Cache the new table position for quick lookups */
606
+ this.s.tableTop = $(this.s.dt.nTable).offset().top;
607
+ this.s.tableBottom = $(this.s.dt.nTable).height() + this.s.tableTop;
608
+
609
+ var draw = function () {
610
+ if ( that.s.scrollDrawReq === null ) {
611
+ that.s.scrollDrawReq = iScrollTop;
612
+ }
613
+
614
+ that.s.dt._iDisplayStart = iTopRow;
615
+ if ( that.s.dt.oApi._fnCalculateEnd ) { // Removed in 1.10
616
+ that.s.dt.oApi._fnCalculateEnd( that.s.dt );
617
+ }
618
+ that.s.dt.oApi._fnDraw( that.s.dt );
619
+ };
620
+
621
+ /* Do the DataTables redraw based on the calculated start point - note that when
622
+ * using server-side processing we introduce a small delay to not DoS the server...
623
+ */
624
+ if ( this.s.dt.oFeatures.bServerSide ) {
625
+ clearTimeout( this.s.drawTO );
626
+ this.s.drawTO = setTimeout( draw, this.s.serverWait );
627
+ }
628
+ else {
629
+ draw();
630
+ }
631
+ }
632
+ }
633
+
634
+ this.s.lastScrollTop = iScrollTop;
635
+ },
636
+
637
+
638
+ /**
639
+ * Convert from one domain to another. The physical domain is the actual
640
+ * pixel count on the screen, while the virtual is if we had browsers which
641
+ * had scrolling containers of infinite height (i.e. the absolute value)
642
+ *
643
+ * @param {string} dir Domain transform direction, `virtualToPhysical` or
644
+ * `physicalToVirtual`
645
+ * @returns {number} Calculated transform
646
+ * @private
647
+ */
648
+ _domain: function ( dir, val )
649
+ {
650
+ var heights = this.s.heights;
651
+ var coeff;
652
+
653
+ // If the virtual and physical height match, then we use a linear
654
+ // transform between the two, allowing the scrollbar to be linear
655
+ if ( heights.virtual === heights.scroll ) {
656
+ coeff = (heights.virtual-heights.viewport) / (heights.scroll-heights.viewport);
657
+
658
+ if ( dir === 'virtualToPhysical' ) {
659
+ return val / coeff;
660
+ }
661
+ else if ( dir === 'physicalToVirtual' ) {
662
+ return val * coeff;
663
+ }
664
+ }
665
+
666
+ // Otherwise, we want a non-linear scrollbar to take account of the
667
+ // redrawing regions at the start and end of the table, otherwise these
668
+ // can stutter badly - on large tables 30px (for example) scroll might
669
+ // be hundreds of rows, so the table would be redrawing every few px at
670
+ // the start and end. Use a simple quadratic to stop this. It does mean
671
+ // the scrollbar is non-linear, but with such massive data sets, the
672
+ // scrollbar is going to be a best guess anyway
673
+ var xMax = (heights.scroll - heights.viewport) / 2;
674
+ var yMax = (heights.virtual - heights.viewport) / 2;
675
+
676
+ coeff = yMax / ( xMax * xMax );
677
+
678
+ if ( dir === 'virtualToPhysical' ) {
679
+ if ( val < yMax ) {
680
+ return Math.pow(val / coeff, 0.5);
681
+ }
682
+ else {
683
+ val = (yMax*2) - val;
684
+ return val < 0 ?
685
+ heights.scroll :
686
+ (xMax*2) - Math.pow(val / coeff, 0.5);
687
+ }
688
+ }
689
+ else if ( dir === 'physicalToVirtual' ) {
690
+ if ( val < xMax ) {
691
+ return val * val * coeff;
692
+ }
693
+ else {
694
+ val = (xMax*2) - val;
695
+ return val < 0 ?
696
+ heights.virtual :
697
+ (yMax*2) - (val * val * coeff);
698
+ }
699
+ }
700
+ },
701
+
702
+
703
+ /**
704
+ * Draw callback function which is fired when the DataTable is redrawn. The main function of
705
+ * this method is to position the drawn table correctly the scrolling container for the rows
706
+ * that is displays as a result of the scrolling position.
707
+ * @returns {void}
708
+ * @private
709
+ */
710
+ "_fnDrawCallback": function ()
711
+ {
712
+ var
713
+ that = this,
714
+ heights = this.s.heights,
715
+ iScrollTop = this.dom.scroller.scrollTop,
716
+ iActualScrollTop = iScrollTop,
717
+ iScrollBottom = iScrollTop + heights.viewport,
718
+ iTableHeight = $(this.s.dt.nTable).height(),
719
+ displayStart = this.s.dt._iDisplayStart,
720
+ displayLen = this.s.dt._iDisplayLength,
721
+ displayEnd = this.s.dt.fnRecordsDisplay();
722
+
723
+ // Disable the scroll event listener while we are updating the DOM
724
+ this.s.skip = true;
725
+
726
+ // Resize the scroll forcing element
727
+ this._fnScrollForce();
728
+
729
+ // Reposition the scrolling for the updated virtual position if needed
730
+ if ( displayStart === 0 ) {
731
+ // Linear calculation at the top of the table
732
+ iScrollTop = this.s.topRowFloat * heights.row;
733
+ }
734
+ else if ( displayStart + displayLen >= displayEnd ) {
735
+ // Linear calculation that the bottom as well
736
+ iScrollTop = heights.scroll - ((displayEnd - this.s.topRowFloat) * heights.row);
737
+ }
738
+ else {
739
+ // Domain scaled in the middle
740
+ iScrollTop = this._domain( 'virtualToPhysical', this.s.topRowFloat * heights.row );
741
+ }
742
+
743
+ this.dom.scroller.scrollTop = iScrollTop;
744
+
745
+ // Store positional information so positional calculations can be based
746
+ // upon the current table draw position
747
+ this.s.baseScrollTop = iScrollTop;
748
+ this.s.baseRowTop = this.s.topRowFloat;
749
+
750
+ // Position the table in the virtual scroller
751
+ var tableTop = iScrollTop - ((this.s.topRowFloat - displayStart) * heights.row);
752
+ if ( displayStart === 0 ) {
753
+ tableTop = 0;
754
+ }
755
+ else if ( displayStart + displayLen >= displayEnd ) {
756
+ tableTop = heights.scroll - iTableHeight;
757
+ }
758
+
759
+ this.dom.table.style.top = tableTop+'px';
760
+
761
+ /* Cache some information for the scroller */
762
+ this.s.tableTop = tableTop;
763
+ this.s.tableBottom = iTableHeight + this.s.tableTop;
764
+
765
+ // Calculate the boundaries for where a redraw will be triggered by the
766
+ // scroll event listener
767
+ var boundaryPx = (iScrollTop - this.s.tableTop) * this.s.boundaryScale;
768
+ this.s.redrawTop = iScrollTop - boundaryPx;
769
+ this.s.redrawBottom = iScrollTop + boundaryPx;
770
+
771
+ this.s.skip = false;
772
+
773
+ // Because of the order of the DT callbacks, the info update will
774
+ // take precidence over the one we want here. So a 'thread' break is
775
+ // needed
776
+ setTimeout( function () {
777
+ that._fnInfo.call( that );
778
+ }, 0 );
779
+
780
+ // Restore the scrolling position that was saved by DataTable's state
781
+ // saving Note that this is done on the second draw when data is Ajax
782
+ // sourced, and the first draw when DOM soured
783
+ if ( this.s.dt.oFeatures.bStateSave && this.s.dt.oLoadedState !== null &&
784
+ typeof this.s.dt.oLoadedState.iScroller != 'undefined' )
785
+ {
786
+ var ajaxSourced = this.s.dt.sAjaxSource || that.s.dt.ajax ?
787
+ true :
788
+ false;
789
+
790
+ if ( ( ajaxSourced && this.s.dt.iDraw == 2) ||
791
+ (!ajaxSourced && this.s.dt.iDraw == 1) )
792
+ {
793
+ setTimeout( function () {
794
+ $(that.dom.scroller).scrollTop( that.s.dt.oLoadedState.iScroller );
795
+ that.s.redrawTop = that.s.dt.oLoadedState.iScroller - (heights.viewport/2);
796
+ }, 0 );
797
+ }
798
+ }
799
+ },
800
+
801
+
802
+ /**
803
+ * Force the scrolling container to have height beyond that of just the
804
+ * table that has been drawn so the user can scroll the whole data set.
805
+ *
806
+ * Note that if the calculated required scrolling height exceeds a maximum
807
+ * value (1 million pixels - hard-coded) the forcing element will be set
808
+ * only to that maximum value and virtual / physical domain transforms will
809
+ * be used to allow Scroller to display tables of any number of records.
810
+ * @returns {void}
811
+ * @private
812
+ */
813
+ _fnScrollForce: function ()
814
+ {
815
+ var heights = this.s.heights;
816
+ var max = 1000000;
817
+
818
+ heights.virtual = heights.row * this.s.dt.fnRecordsDisplay();
819
+ heights.scroll = heights.virtual;
820
+
821
+ if ( heights.scroll > max ) {
822
+ heights.scroll = max;
823
+ }
824
+
825
+ this.dom.force.style.height = heights.scroll+"px";
826
+ },
827
+
828
+
829
+ /**
830
+ * Automatic calculation of table row height. This is just a little tricky here as using
831
+ * initialisation DataTables has tale the table out of the document, so we need to create
832
+ * a new table and insert it into the document, calculate the row height and then whip the
833
+ * table out.
834
+ * @returns {void}
835
+ * @private
836
+ */
837
+ "_fnCalcRowHeight": function ()
838
+ {
839
+ var origTable = this.s.dt.nTable;
840
+ var nTable = origTable.cloneNode( false );
841
+ var tbody = $('<tbody/>').appendTo( nTable );
842
+ var container = $(
843
+ '<div class="'+this.s.dt.oClasses.sWrapper+' DTS">'+
844
+ '<div class="'+this.s.dt.oClasses.sScrollWrapper+'">'+
845
+ '<div class="'+this.s.dt.oClasses.sScrollBody+'"></div>'+
846
+ '</div>'+
847
+ '</div>'
848
+ );
849
+
850
+ // Want 3 rows in the sizing table so :first-child and :last-child
851
+ // CSS styles don't come into play - take the size of the middle row
852
+ $('tbody tr:lt(4)', origTable).clone().appendTo( tbody );
853
+ while( $('tr', tbody).length < 3 ) {
854
+ tbody.append( '<tr><td>&nbsp;</td></tr>' );
855
+ }
856
+
857
+ $('div.'+this.s.dt.oClasses.sScrollBody, container).append( nTable );
858
+
859
+ container.appendTo( this.s.dt.nHolding );
860
+ this.s.heights.row = $('tr', tbody).eq(1).outerHeight();
861
+ container.remove();
862
+ },
863
+
864
+
865
+ /**
866
+ * Update any information elements that are controlled by the DataTable based on the scrolling
867
+ * viewport and what rows are visible in it. This function basically acts in the same way as
868
+ * _fnUpdateInfo in DataTables, and effectively replaces that function.
869
+ * @returns {void}
870
+ * @private
871
+ */
872
+ "_fnInfo": function ()
873
+ {
874
+ if ( !this.s.dt.oFeatures.bInfo )
875
+ {
876
+ return;
877
+ }
878
+
879
+ var
880
+ dt = this.s.dt,
881
+ iScrollTop = this.dom.scroller.scrollTop,
882
+ iStart = Math.floor( this.fnPixelsToRow(iScrollTop, false, this.s.ani)+1 ),
883
+ iMax = dt.fnRecordsTotal(),
884
+ iTotal = dt.fnRecordsDisplay(),
885
+ iPossibleEnd = Math.ceil( this.fnPixelsToRow(iScrollTop+this.s.heights.viewport, false, this.s.ani) ),
886
+ iEnd = iTotal < iPossibleEnd ? iTotal : iPossibleEnd,
887
+ sStart = dt.fnFormatNumber( iStart ),
888
+ sEnd = dt.fnFormatNumber( iEnd ),
889
+ sMax = dt.fnFormatNumber( iMax ),
890
+ sTotal = dt.fnFormatNumber( iTotal ),
891
+ sOut;
892
+
893
+ if ( dt.fnRecordsDisplay() === 0 &&
894
+ dt.fnRecordsDisplay() == dt.fnRecordsTotal() )
895
+ {
896
+ /* Empty record set */
897
+ sOut = dt.oLanguage.sInfoEmpty+ dt.oLanguage.sInfoPostFix;
898
+ }
899
+ else if ( dt.fnRecordsDisplay() === 0 )
900
+ {
901
+ /* Rmpty record set after filtering */
902
+ sOut = dt.oLanguage.sInfoEmpty +' '+
903
+ dt.oLanguage.sInfoFiltered.replace('_MAX_', sMax)+
904
+ dt.oLanguage.sInfoPostFix;
905
+ }
906
+ else if ( dt.fnRecordsDisplay() == dt.fnRecordsTotal() )
907
+ {
908
+ /* Normal record set */
909
+ sOut = dt.oLanguage.sInfo.
910
+ replace('_START_', sStart).
911
+ replace('_END_', sEnd).
912
+ replace('_TOTAL_', sTotal)+
913
+ dt.oLanguage.sInfoPostFix;
914
+ }
915
+ else
916
+ {
917
+ /* Record set after filtering */
918
+ sOut = dt.oLanguage.sInfo.
919
+ replace('_START_', sStart).
920
+ replace('_END_', sEnd).
921
+ replace('_TOTAL_', sTotal) +' '+
922
+ dt.oLanguage.sInfoFiltered.replace('_MAX_',
923
+ dt.fnFormatNumber(dt.fnRecordsTotal()))+
924
+ dt.oLanguage.sInfoPostFix;
925
+ }
926
+
927
+ var n = dt.aanFeatures.i;
928
+ if ( typeof n != 'undefined' )
929
+ {
930
+ for ( var i=0, iLen=n.length ; i<iLen ; i++ )
931
+ {
932
+ $(n[i]).html( sOut );
933
+ }
934
+ }
935
+ }
936
+ };
937
+
938
+
939
+
940
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
941
+ * Statics
942
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
943
+
944
+
945
+ /**
946
+ * Scroller default settings for initialisation
947
+ * @namespace
948
+ * @name Scroller.defaults
949
+ * @static
950
+ */
951
+ Scroller.defaults = /** @lends Scroller.defaults */{
952
+ /**
953
+ * Indicate if Scroller show show trace information on the console or not. This can be
954
+ * useful when debugging Scroller or if just curious as to what it is doing, but should
955
+ * be turned off for production.
956
+ * @type bool
957
+ * @default false
958
+ * @static
959
+ * @example
960
+ * var oTable = $('#example').dataTable( {
961
+ * "sScrollY": "200px",
962
+ * "sDom": "frtiS",
963
+ * "bDeferRender": true,
964
+ * "oScroller": {
965
+ * "trace": true
966
+ * }
967
+ * } );
968
+ */
969
+ "trace": false,
970
+
971
+ /**
972
+ * Scroller will attempt to automatically calculate the height of rows for it's internal
973
+ * calculations. However the height that is used can be overridden using this parameter.
974
+ * @type int|string
975
+ * @default auto
976
+ * @static
977
+ * @example
978
+ * var oTable = $('#example').dataTable( {
979
+ * "sScrollY": "200px",
980
+ * "sDom": "frtiS",
981
+ * "bDeferRender": true,
982
+ * "oScroller": {
983
+ * "rowHeight": 30
984
+ * }
985
+ * } );
986
+ */
987
+ "rowHeight": "auto",
988
+
989
+ /**
990
+ * When using server-side processing, Scroller will wait a small amount of time to allow
991
+ * the scrolling to finish before requesting more data from the server. This prevents
992
+ * you from DoSing your own server! The wait time can be configured by this parameter.
993
+ * @type int
994
+ * @default 200
995
+ * @static
996
+ * @example
997
+ * var oTable = $('#example').dataTable( {
998
+ * "sScrollY": "200px",
999
+ * "sDom": "frtiS",
1000
+ * "bDeferRender": true,
1001
+ * "oScroller": {
1002
+ * "serverWait": 100
1003
+ * }
1004
+ * } );
1005
+ */
1006
+ "serverWait": 200,
1007
+
1008
+ /**
1009
+ * The display buffer is what Scroller uses to calculate how many rows it should pre-fetch
1010
+ * for scrolling. Scroller automatically adjusts DataTables' display length to pre-fetch
1011
+ * rows that will be shown in "near scrolling" (i.e. just beyond the current display area).
1012
+ * The value is based upon the number of rows that can be displayed in the viewport (i.e.
1013
+ * a value of 1), and will apply the display range to records before before and after the
1014
+ * current viewport - i.e. a factor of 3 will allow Scroller to pre-fetch 1 viewport's worth
1015
+ * of rows before the current viewport, the current viewport's rows and 1 viewport's worth
1016
+ * of rows after the current viewport. Adjusting this value can be useful for ensuring
1017
+ * smooth scrolling based on your data set.
1018
+ * @type int
1019
+ * @default 7
1020
+ * @static
1021
+ * @example
1022
+ * var oTable = $('#example').dataTable( {
1023
+ * "sScrollY": "200px",
1024
+ * "sDom": "frtiS",
1025
+ * "bDeferRender": true,
1026
+ * "oScroller": {
1027
+ * "displayBuffer": 10
1028
+ * }
1029
+ * } );
1030
+ */
1031
+ "displayBuffer": 9,
1032
+
1033
+ /**
1034
+ * Scroller uses the boundary scaling factor to decide when to redraw the table - which it
1035
+ * typically does before you reach the end of the currently loaded data set (in order to
1036
+ * allow the data to look continuous to a user scrolling through the data). If given as 0
1037
+ * then the table will be redrawn whenever the viewport is scrolled, while 1 would not
1038
+ * redraw the table until the currently loaded data has all been shown. You will want
1039
+ * something in the middle - the default factor of 0.5 is usually suitable.
1040
+ * @type float
1041
+ * @default 0.5
1042
+ * @static
1043
+ * @example
1044
+ * var oTable = $('#example').dataTable( {
1045
+ * "sScrollY": "200px",
1046
+ * "sDom": "frtiS",
1047
+ * "bDeferRender": true,
1048
+ * "oScroller": {
1049
+ * "boundaryScale": 0.75
1050
+ * }
1051
+ * } );
1052
+ */
1053
+ "boundaryScale": 0.5,
1054
+
1055
+ /**
1056
+ * Show (or not) the loading element in the background of the table. Note that you should
1057
+ * include the dataTables.scroller.css file for this to be displayed correctly.
1058
+ * @type boolean
1059
+ * @default false
1060
+ * @static
1061
+ * @example
1062
+ * var oTable = $('#example').dataTable( {
1063
+ * "sScrollY": "200px",
1064
+ * "sDom": "frtiS",
1065
+ * "bDeferRender": true,
1066
+ * "oScroller": {
1067
+ * "loadingIndicator": true
1068
+ * }
1069
+ * } );
1070
+ */
1071
+ "loadingIndicator": false
1072
+ };
1073
+
1074
+ Scroller.oDefaults = Scroller.defaults;
1075
+
1076
+
1077
+
1078
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1079
+ * Constants
1080
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1081
+
1082
+ /**
1083
+ * Scroller version
1084
+ * @type String
1085
+ * @default See code
1086
+ * @name Scroller.version
1087
+ * @static
1088
+ */
1089
+ Scroller.version = "1.2.1";
1090
+
1091
+
1092
+
1093
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1094
+ * Initialisation
1095
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1096
+
1097
+ /*
1098
+ * Register a new feature with DataTables
1099
+ */
1100
+ if ( typeof $.fn.dataTable == "function" &&
1101
+ typeof $.fn.dataTableExt.fnVersionCheck == "function" &&
1102
+ $.fn.dataTableExt.fnVersionCheck('1.9.0') )
1103
+ {
1104
+ $.fn.dataTableExt.aoFeatures.push( {
1105
+ "fnInit": function( oDTSettings ) {
1106
+ var init = oDTSettings.oInit;
1107
+ var opts = init.scroller || init.oScroller || {};
1108
+ var oScroller = new Scroller( oDTSettings, opts );
1109
+ return oScroller.dom.wrapper;
1110
+ },
1111
+ "cFeature": "S",
1112
+ "sFeature": "Scroller"
1113
+ } );
1114
+ }
1115
+ else
1116
+ {
1117
+ alert( "Warning: Scroller requires DataTables 1.9.0 or greater - www.datatables.net/download");
1118
+ }
1119
+
1120
+
1121
+ // Attach Scroller to DataTables so it can be accessed as an 'extra'
1122
+ $.fn.dataTable.Scroller = Scroller;
1123
+ $.fn.DataTable.Scroller = Scroller;
1124
+
1125
+
1126
+ // DataTables 1.10 API method aliases
1127
+ if ( $.fn.dataTable.Api ) {
1128
+ var Api = $.fn.dataTable.Api;
1129
+
1130
+ Api.register( 'scroller().rowToPixels()', function ( rowIdx, intParse, virtual ) {
1131
+ var ctx = this.context;
1132
+
1133
+ if ( ctx.length && ctx[0].oScroller ) {
1134
+ return ctx[0].oScroller.fnRowToPixels( rowIdx, intParse, virtual );
1135
+ }
1136
+ // undefined
1137
+ } );
1138
+
1139
+ Api.register( 'scroller().pixelsToRow()', function ( pixels, intParse, virtual ) {
1140
+ var ctx = this.context;
1141
+
1142
+ if ( ctx.length && ctx[0].oScroller ) {
1143
+ return ctx[0].oScroller.fnPixelsToRow( pixels, intParse, virtual );
1144
+ }
1145
+ // undefined
1146
+ } );
1147
+
1148
+ Api.register( 'scroller().scrollToRow()', function ( row, ani ) {
1149
+ this.iterator( 'table', function ( ctx ) {
1150
+ if ( ctx.oScroller ) {
1151
+ ctx.oScroller.fnScrollToRow( row, ani );
1152
+ }
1153
+ } );
1154
+
1155
+ return this;
1156
+ } );
1157
+
1158
+ Api.register( 'scroller().measure()', function ( redraw ) {
1159
+ this.iterator( 'table', function ( ctx ) {
1160
+ if ( ctx.oScroller ) {
1161
+ ctx.oScroller.fnMeasure( redraw );
1162
+ }
1163
+ } );
1164
+
1165
+ return this;
1166
+ } );
1167
+ }
1168
+
1169
+
1170
+ return Scroller;
1171
+ }; // /factory
1172
+
1173
+
1174
+ // Define as an AMD module if possible
1175
+ if ( typeof define === 'function' && define.amd ) {
1176
+ define( 'datatables-scroller', ['jquery', 'datatables'], factory );
1177
+ }
1178
+ else if ( jQuery && !jQuery.fn.dataTable.Scroller ) {
1179
+ // Otherwise simply initialise as normal, stopping multiple evaluation
1180
+ factory( jQuery, jQuery.fn.dataTable );
1181
+ }
1182
+
1183
+
1184
+ })(window, document);
1185
+