lanes 0.1.9.5 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (304) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +1 -0
  3. data/Rakefile +1 -1
  4. data/client/lanes/Boot.cjsx +3 -3
  5. data/client/lanes/Config.coffee +38 -3
  6. data/client/lanes/access/Extension.coffee +1 -1
  7. data/client/lanes/access/LoginDialog.cjsx +57 -47
  8. data/client/lanes/access/Roles.coffee +2 -2
  9. data/client/lanes/access/User.coffee +4 -3
  10. data/client/lanes/access/screens/user-management/UserManagement.cjsx +12 -11
  11. data/client/lanes/components/calendar/Calendar.cjsx +16 -0
  12. data/client/lanes/components/calendar/index.js +3 -0
  13. data/client/lanes/components/calendar/styles.scss +3 -0
  14. data/client/lanes/components/grid/Body.cjsx +86 -0
  15. data/client/lanes/components/grid/CellStyles.coffee +20 -0
  16. data/client/lanes/components/grid/EditingMixin.cjsx +84 -24
  17. data/client/lanes/components/grid/Editor.cjsx +45 -0
  18. data/client/lanes/components/grid/Grid.cjsx +62 -104
  19. data/client/lanes/components/grid/Header.cjsx +35 -0
  20. data/client/lanes/components/grid/PopOverMixin.cjsx +19 -9
  21. data/client/lanes/components/grid/PopoverEditor.cjsx +7 -1
  22. data/client/lanes/components/grid/RowEditor.cjsx +1 -1
  23. data/client/lanes/components/grid/Selections.cjsx +39 -0
  24. data/client/lanes/components/grid/Toolbar.cjsx +24 -5
  25. data/client/lanes/components/grid/editors.scss +22 -50
  26. data/client/lanes/components/grid/index.js +0 -1
  27. data/client/lanes/components/grid/row-editor.scss +68 -0
  28. data/client/lanes/components/grid/styles.scss +79 -3
  29. data/client/lanes/components/modal/Modal.cjsx +64 -24
  30. data/client/lanes/components/modal/styles.scss +12 -0
  31. data/client/lanes/components/record-finder/Clause.cjsx +11 -4
  32. data/client/lanes/components/record-finder/Dialog.cjsx +23 -24
  33. data/client/lanes/components/record-finder/RecordFinder.cjsx +45 -14
  34. data/client/lanes/components/record-finder/styles.scss +9 -6
  35. data/client/lanes/components/select-field/SelectField.cjsx +108 -53
  36. data/client/lanes/components/select-field/styles.scss +19 -0
  37. data/client/lanes/components/shared/ControlLabel.cjsx +45 -0
  38. data/client/lanes/components/shared/DateTime.cjsx +48 -0
  39. data/client/lanes/components/shared/DisplayValue.cjsx +16 -0
  40. data/client/lanes/components/shared/FieldMixin.cjsx +54 -23
  41. data/client/lanes/components/shared/FieldSet.cjsx +12 -35
  42. data/client/lanes/components/shared/FieldWrapper.cjsx +13 -0
  43. data/client/lanes/components/shared/FormGroup.cjsx +37 -0
  44. data/client/lanes/components/shared/Icon.cjsx +20 -0
  45. data/client/lanes/components/shared/ImageSaver.cjsx +33 -0
  46. data/client/lanes/components/shared/Input.cjsx +19 -0
  47. data/client/lanes/components/shared/InputFieldMixin.cjsx +48 -0
  48. data/client/lanes/components/shared/JobProgress.cjsx +27 -0
  49. data/client/lanes/components/shared/NetworkActivityOverlay.cjsx +58 -0
  50. data/client/lanes/components/shared/NumberInput.cjsx +29 -0
  51. data/client/lanes/components/shared/ResizeSensor.cjsx +11 -0
  52. data/client/lanes/components/shared/ScreenWrapper.cjsx +13 -0
  53. data/client/lanes/components/shared/Throbber.cjsx +3 -0
  54. data/client/lanes/components/shared/ToggleField.cjsx +33 -0
  55. data/client/lanes/components/shared/Tooltip.cjsx +2 -2
  56. data/client/lanes/components/shared/fields.scss +75 -13
  57. data/client/lanes/components/shared/fieldset.scss +3 -5
  58. data/client/lanes/components/shared/image-saver.scss +38 -0
  59. data/client/lanes/components/shared/index.js +2 -0
  60. data/client/lanes/{styles/plugins → components/shared}/overlay.scss +17 -4
  61. data/client/lanes/components/shared/resize-sensor.scss +30 -0
  62. data/client/lanes/components/shared/styles.scss +13 -0
  63. data/client/lanes/components/shared/throbber.scss +53 -0
  64. data/client/lanes/components/toolbar/RemoteChangeSets.cjsx +21 -48
  65. data/client/lanes/components/toolbar/SaveButton.cjsx +24 -0
  66. data/client/lanes/components/toolbar/Toolbar.cjsx +24 -37
  67. data/client/lanes/components/toolbar/changes-notification.scss +10 -6
  68. data/client/lanes/components/toolbar/styles.scss +29 -9
  69. data/client/lanes/extension/Base.coffee +4 -5
  70. data/client/lanes/index.js +0 -1
  71. data/client/lanes/index.scss.erb +10 -1
  72. data/client/lanes/lib/HotReload.coffee +13 -15
  73. data/client/lanes/lib/MakeBaseClass.coffee +6 -1
  74. data/client/lanes/lib/development.coffee +2 -0
  75. data/client/lanes/lib/dom-polyfills.coffee +5 -0
  76. data/client/lanes/lib/dom.coffee +38 -9
  77. data/client/lanes/lib/format.coffee +11 -0
  78. data/client/lanes/lib/index.js.erb +2 -0
  79. data/client/lanes/lib/production.coffee +6 -0
  80. data/client/lanes/lib/utilFunctions.coffee +50 -15
  81. data/client/lanes/models/AssociationMap.coffee +122 -46
  82. data/client/lanes/models/AssociationProxy.coffee +147 -0
  83. data/client/lanes/models/Base.coffee +97 -85
  84. data/client/lanes/models/ChangeMonitor.coffee +7 -3
  85. data/client/lanes/models/ChangeSet.coffee +2 -2
  86. data/client/lanes/models/Collection.coffee +49 -6
  87. data/client/lanes/models/JobStatus.coffee +32 -0
  88. data/client/lanes/models/PubSub.coffee +7 -5
  89. data/client/lanes/models/Query.coffee +115 -34
  90. data/client/lanes/models/ServerCache.coffee +67 -52
  91. data/client/lanes/models/State.coffee +97 -0
  92. data/client/lanes/models/Sync.coffee +18 -13
  93. data/client/lanes/models/SystemSettings.coffee +0 -0
  94. data/client/lanes/models/index.js +1 -0
  95. data/client/lanes/models/mixins/FileSupport.coffee +60 -0
  96. data/client/lanes/models/mixins/HasCodeField.coffee +13 -6
  97. data/client/lanes/models/query/ArrayResult.coffee +188 -0
  98. data/client/lanes/models/query/CollectionResult.coffee +71 -0
  99. data/client/lanes/models/query/Result.coffee +9 -0
  100. data/client/lanes/react/Component.coffee +7 -3
  101. data/client/lanes/react/PubSub.coffee +7 -7
  102. data/client/lanes/react/Root.cjsx +1 -4
  103. data/client/lanes/react/Screen.coffee +1 -0
  104. data/client/lanes/react/TypeValidators.coffee +3 -3
  105. data/client/lanes/react/Viewport.coffee +41 -7
  106. data/client/lanes/react/index.js +0 -1
  107. data/client/lanes/react/mixins/Access.coffee +4 -1
  108. data/client/lanes/react/mixins/Data.coffee +40 -25
  109. data/client/lanes/react/mixins/FieldErrors.coffee +27 -0
  110. data/client/lanes/react/mixins/RelayEditingState.coffee +4 -0
  111. data/client/lanes/react/mixins/Screen.coffee +14 -0
  112. data/client/lanes/react/mixins/Viewport.coffee +9 -3
  113. data/client/lanes/screens/ChangeListener.coffee +3 -3
  114. data/client/lanes/screens/Commands.coffee +14 -7
  115. data/client/lanes/screens/CommonComponents.cjsx +20 -0
  116. data/client/lanes/screens/Definitions.coffee +64 -20
  117. data/client/lanes/screens/SystemSettings.cjsx +56 -0
  118. data/client/lanes/screens/UserPreferences.cjsx +38 -0
  119. data/client/lanes/screens/index.js +3 -0
  120. data/client/lanes/screens/styles.scss +2 -1
  121. data/client/lanes/styles/fonts.scss +1 -0
  122. data/client/lanes/styles/global.scss +2 -1
  123. data/client/lanes/styles/global/flexbox.scss +16 -0
  124. data/client/lanes/styles/global/styles.scss +1 -0
  125. data/client/lanes/styles/mixins/_dropdown.scss +21 -0
  126. data/client/lanes/styles/mixins/_flexbox.scss +394 -0
  127. data/client/lanes/styles/mixins/all.scss +2 -0
  128. data/client/lanes/styles/variables.scss +28 -0
  129. data/client/lanes/testing/BeforeEach.coffee +15 -14
  130. data/client/lanes/testing/Helpers.coffee +14 -5
  131. data/client/lanes/testing/TestObjects.coffee +10 -2
  132. data/client/lanes/testing/index.js +1 -0
  133. data/client/lanes/testing/jasmine-react.js +125 -0
  134. data/client/lanes/vendor/base.js +56049 -74987
  135. data/client/lanes/vendor/calendar.js +17301 -0
  136. data/client/lanes/vendor/calendar.scss +303 -0
  137. data/client/lanes/vendor/commons.js +14990 -15847
  138. data/client/lanes/vendor/development.js +4912 -1952
  139. data/client/lanes/vendor/grid.js +14246 -5551
  140. data/client/lanes/vendor/grid.scss +876 -335
  141. data/client/lanes/vendor/index.js +1 -0
  142. data/client/lanes/vendor/message-bus-ajax.js +44 -0
  143. data/client/lanes/vendor/message-bus.js +414 -0
  144. data/client/lanes/vendor/rw-widgets.eot +0 -0
  145. data/client/lanes/vendor/rw-widgets.svg +18 -0
  146. data/client/lanes/vendor/rw-widgets.ttf +0 -0
  147. data/client/lanes/vendor/rw-widgets.woff +0 -0
  148. data/client/lanes/vendor/toggle.js +345 -0
  149. data/client/lanes/vendor/toggle.scss +138 -0
  150. data/client/lanes/vendor/widgets.js +21245 -6839
  151. data/client/lanes/vendor/widgets.scss +83 -67
  152. data/client/lanes/workspace/Layout.cjsx +18 -8
  153. data/client/lanes/workspace/Modal.cjsx +47 -0
  154. data/client/lanes/workspace/Navbar.cjsx +16 -2
  155. data/client/lanes/workspace/ScreenView.cjsx +10 -3
  156. data/client/lanes/workspace/ScreensMenu.cjsx +23 -7
  157. data/client/lanes/workspace/Tabs.cjsx +55 -0
  158. data/client/lanes/workspace/UIState.coffee +7 -8
  159. data/client/lanes/workspace/index.js +2 -1
  160. data/client/lanes/workspace/mixin.coffee +11 -0
  161. data/client/lanes/workspace/mixins/UIState.coffee +8 -0
  162. data/client/lanes/workspace/mixins/index.js +3 -0
  163. data/client/lanes/workspace/styles.scss +2 -1
  164. data/client/lanes/workspace/styles/header.scss +23 -1
  165. data/client/lanes/workspace/styles/layout.scss +26 -24
  166. data/client/lanes/workspace/styles/screens.scss +0 -4
  167. data/client/lanes/workspace/styles/tabs.scss +3 -10
  168. data/config/routes.rb +10 -4
  169. data/config/screens.rb +25 -0
  170. data/db/migrate/01_create_system_settings.rb +10 -0
  171. data/docs/todo-example-part-1.md +18 -20
  172. data/lanes.gemspec +15 -6
  173. data/lib/lanes.rb +4 -2
  174. data/lib/lanes/access/config/routes.rb +5 -3
  175. data/lib/lanes/access/config/screens.rb +1 -0
  176. data/lib/lanes/access/db/migrate/20140615031600_create_lanes_users.rb +1 -1
  177. data/lib/lanes/access/user.rb +1 -1
  178. data/lib/lanes/api.rb +2 -1
  179. data/lib/lanes/api/controller.rb +32 -71
  180. data/lib/lanes/api/default_routes.rb +10 -8
  181. data/lib/lanes/api/formatted_reply.rb +53 -0
  182. data/lib/lanes/api/handlers/file.rb +26 -0
  183. data/lib/lanes/api/helper_methods.rb +29 -5
  184. data/lib/lanes/api/javascript_processor.rb +36 -17
  185. data/lib/lanes/api/pub_sub.rb +6 -9
  186. data/lib/lanes/api/request_wrapper.rb +1 -2
  187. data/lib/lanes/api/root.rb +11 -43
  188. data/lib/lanes/api/routing.rb +63 -0
  189. data/lib/lanes/api/sprockets_extension.rb +15 -7
  190. data/lib/lanes/api/updates.rb +1 -2
  191. data/lib/lanes/command.rb +0 -1
  192. data/lib/lanes/command/app.rb +6 -5
  193. data/lib/lanes/command/console.rb +1 -0
  194. data/lib/lanes/command/generate.rb +3 -0
  195. data/lib/lanes/command/generate_migration.rb +33 -0
  196. data/lib/lanes/command/generate_model.rb +4 -26
  197. data/lib/lanes/command/migration_support.rb +29 -0
  198. data/lib/lanes/command/update_model.rb +14 -5
  199. data/lib/lanes/concerns/all.rb +2 -0
  200. data/lib/lanes/concerns/api_path.rb +4 -2
  201. data/lib/lanes/concerns/association_extensions.rb +1 -1
  202. data/lib/lanes/concerns/attr_accessor_with_default.rb +3 -1
  203. data/lib/lanes/concerns/code_identifier.rb +1 -1
  204. data/lib/lanes/concerns/image_uploader.rb +42 -0
  205. data/lib/lanes/concerns/pub_sub.rb +0 -1
  206. data/lib/lanes/concerns/queries.rb +2 -2
  207. data/lib/lanes/concerns/set_attribute_data.rb +4 -13
  208. data/lib/lanes/concerns/sorting_expressions.rb +34 -0
  209. data/lib/lanes/configuration.rb +48 -9
  210. data/lib/lanes/extension.rb +16 -7
  211. data/lib/lanes/extension/definition.rb +8 -2
  212. data/lib/lanes/job.rb +78 -0
  213. data/lib/lanes/job/failure_logger.rb +33 -0
  214. data/lib/lanes/model.rb +4 -0
  215. data/lib/lanes/rake_tasks.rb +6 -0
  216. data/lib/lanes/redis.rb +13 -0
  217. data/lib/lanes/screen.rb +34 -18
  218. data/lib/lanes/system_settings.rb +66 -0
  219. data/lib/lanes/version.rb +1 -1
  220. data/lib/lanes/workspace/extension.rb +1 -1
  221. data/npm-build/base.js +10 -3
  222. data/npm-build/calendar.js +6 -0
  223. data/npm-build/development.js +4 -5
  224. data/npm-build/grid.js +3 -5
  225. data/npm-build/package.json +40 -29
  226. data/npm-build/react-toggle.js +5 -0
  227. data/npm-build/react-widgets.js +6 -0
  228. data/npm-build/update-dayz +14 -0
  229. data/npm-build/webpack.config.js +5 -2
  230. data/spec/command-reference-files/initial/Gemfile +1 -1
  231. data/spec/command-reference-files/initial/config/routes.rb +2 -0
  232. data/spec/command-reference-files/initial/lib/appy-app.rb +4 -0
  233. data/spec/command-reference-files/initial/lib/appy-app/extension.rb +2 -0
  234. data/spec/command-reference-files/initial/spec/server/{spec_helpers.rb → spec_helper.rb} +0 -0
  235. data/spec/command-reference-files/model/config/routes.rb +2 -0
  236. data/spec/command-reference-files/model/spec/server/test_test_spec.rb +1 -1
  237. data/spec/command-reference-files/screen/client/appy-app/screens/ready-set-go/ReadySetGo.cjsx +6 -4
  238. data/spec/command-reference-files/screen/client/appy-app/screens/ready-set-go/index.scss +4 -3
  239. data/spec/command-reference-files/screen/config/screens.rb +4 -2
  240. data/spec/command-reference-files/screen/spec/appy-app/screens/ready-set-go/ReadySetGoSpec.coffee +1 -1
  241. data/spec/fixtures/system_settings.yml +1 -0
  242. data/spec/lanes/components/grid/GridSpec.coffee +56 -31
  243. data/spec/lanes/components/grid/RowEditorSpec.coffee +96 -0
  244. data/spec/lanes/components/select-field/SelectFieldSpec.coffee +99 -0
  245. data/spec/lanes/components/shared/NetworkActivityOverlaySpec.coffee +34 -0
  246. data/spec/lanes/models/AssociationMapSpec.coffee +36 -2
  247. data/spec/lanes/models/AssociationProxySpec.coffee +77 -0
  248. data/spec/lanes/models/BaseSpec.coffee +37 -4
  249. data/spec/lanes/models/CollectionSpec.coffee +11 -17
  250. data/spec/lanes/models/PubSubSpec.coffee +1 -1
  251. data/spec/lanes/models/ServerCacheSpec.coffee +65 -0
  252. data/spec/server/api/coffeescript_processor_spec.rb +1 -1
  253. data/spec/server/concerns/pub_sub_spec.rb +9 -10
  254. data/spec/server/concerns/sorting_expressions_spec.rb +34 -0
  255. data/spec/server/configuration_spec.rb +3 -3
  256. data/spec/server/job_spec.rb +54 -0
  257. data/spec/server/spec_helper.rb +0 -5
  258. data/spec/server/system_settings_spec.rb +23 -0
  259. data/templates/client/screens/Screen.cjsx +6 -4
  260. data/templates/client/screens/styles.scss +4 -3
  261. data/templates/config/routes.rb +2 -0
  262. data/templates/config/screen.rb +4 -2
  263. data/templates/lib/namespace.rb +4 -0
  264. data/templates/lib/namespace/extension.rb +2 -0
  265. data/templates/spec/client/Screen.coffee +1 -1
  266. data/templates/spec/server/model_spec.rb +1 -1
  267. data/templates/spec/server/{spec_helpers.rb → spec_helper.rb} +0 -0
  268. data/views/lanes_root_view.erb +70 -0
  269. data/views/specs.erb +2 -2
  270. metadata +207 -68
  271. data/client/images/lanes/dataTables/Sorting icons.psd +0 -0
  272. data/client/images/lanes/dataTables/back_disabled.png +0 -0
  273. data/client/images/lanes/dataTables/back_enabled.png +0 -0
  274. data/client/images/lanes/dataTables/back_enabled_hover.png +0 -0
  275. data/client/images/lanes/dataTables/favicon.ico +0 -0
  276. data/client/images/lanes/dataTables/forward_disabled.png +0 -0
  277. data/client/images/lanes/dataTables/forward_enabled.png +0 -0
  278. data/client/images/lanes/dataTables/forward_enabled_hover.png +0 -0
  279. data/client/images/lanes/dataTables/loading-background.png +0 -0
  280. data/client/images/lanes/dataTables/sort_asc.png +0 -0
  281. data/client/images/lanes/dataTables/sort_asc_disabled.png +0 -0
  282. data/client/images/lanes/dataTables/sort_both.png +0 -0
  283. data/client/images/lanes/dataTables/sort_desc.png +0 -0
  284. data/client/images/lanes/dataTables/sort_desc_disabled.png +0 -0
  285. data/client/lanes/components/shared/Resize.cjsx +0 -152
  286. data/client/lanes/components/shared/TextArea.cjsx +0 -19
  287. data/client/lanes/components/shared/TextField.cjsx +0 -25
  288. data/client/lanes/models/Bootstrap.coffee +0 -5
  289. data/client/lanes/models/QueryResults.coffee +0 -93
  290. data/client/lanes/react/FormBindings.coffee +0 -103
  291. data/client/lanes/react/Router.cjsx +0 -18
  292. data/client/lanes/styles/dataTables.scss +0 -4
  293. data/client/lanes/styles/plugins/all.scss +0 -2
  294. data/client/lanes/styles/plugins/resize-sensor.scss +0 -24
  295. data/client/lanes/vendor/jquery-2.js +0 -9190
  296. data/client/lanes/vendor/jquery.tap.js +0 -401
  297. data/client/lanes/vendor/magicsuggest.js +0 -1565
  298. data/client/lanes/vendor/message-bus.coffee +0 -264
  299. data/client/lanes/workspace/ActiveScreenSwitcher.cjsx +0 -38
  300. data/client/lanes/workspace/styles/toolbar.scss +0 -4
  301. data/lib/lanes/api/eco.js +0 -516
  302. data/lib/lanes/api/sprockets_compressor.rb +0 -39
  303. data/spec/command-reference-files/model/lib/appy-app.rb +0 -11
  304. data/views/index.erb +0 -19
@@ -1,13 +1,15 @@
1
- REACT_CACHE = {}
1
+ REACT_CACHE = Object.create(null)
2
2
 
3
3
  Lanes.lib.HotReload =
4
4
 
5
- rememberReact: (klass) ->
6
- return unless klass::FILE
5
+ remember: (klass) ->
6
+ return klass unless klass::FILE
7
7
  path = klass::FILE.path.join("/") + ".js"
8
- unless REACT_CACHE[path]
9
- REACT_CACHE[path] = klass
10
- Lanes.Vendor.hotRL(klass, path)
8
+ if REACT_CACHE[path]
9
+ return klass
10
+ else
11
+ REACT_CACHE[path] = Lanes.Vendor.ReactProxy(klass)
12
+ return REACT_CACHE[path].get()
11
13
 
12
14
  replaceCss: (asset) ->
13
15
  styles = document.head.querySelectorAll("link[rel='stylesheet'][href*='#{asset.path}']")
@@ -15,17 +17,13 @@ Lanes.lib.HotReload =
15
17
  link.parentElement.removeChild(link)
16
18
 
17
19
  replaceProps: (asset) ->
18
- klass = Lanes.u.objectForPath(asset.path) # Lanes.StockorDemo.LoginDialog
19
- Lanes.Vendor.hotRL(klass, asset.path) if klass
20
-
21
- # Need to copy new proto over the old one
22
- # unsure how to identify new and old one's though
23
- # else
24
- # for klass in prev
20
+ klass = Lanes.u.objectForPath(asset.path)
21
+ if klass and REACT_CACHE[asset.path]
22
+ REACT_CACHE[asset.path].update(klass)
23
+ for viewport in Lanes.React.Viewport.all()
24
+ Lanes.Vendor.deepForceUpdate(viewport.reactRoot)
25
25
 
26
26
  initiate: (assets) ->
27
- console.log _.pluck(assets, 'path')
28
-
29
27
  Lanes.lib.RequestAssets (_.pluck(assets, 'path'))...
30
28
  .then (a) =>
31
29
  for asset in assets
@@ -13,7 +13,12 @@ if Function::name == undefined && Object.defineProperty != undefined
13
13
  mixinModules = (klass) ->
14
14
  Lanes.lib.ModuleSupport.includeInto(klass)
15
15
  if klass::mixins
16
- klass.include(Lanes.u.getPath(mixin, klass::FILE?.namespace)) for mixin in klass::mixins
16
+ for mixin in klass::mixins
17
+ if _.isString(mixin) and klass::FILE
18
+ part = _.classify(klass::FILE.path[1])
19
+ mixin = klass::FILE.namespace[part]?.Mixins[mixin] || Lanes[part]?.Mixins[mixin]
20
+ klass.include(mixin) if mixin
21
+
17
22
 
18
23
  extendProperties = (parent, child) ->
19
24
  child::extendedProperties = _.uniq(
@@ -1,3 +1,5 @@
1
1
  ##= require ./HotReload
2
2
  ##= require lanes/vendor/development
3
3
  ##= require_self
4
+
5
+ Lanes.log.setDefaultLevel(Lanes.log.levels.TRACE)
@@ -0,0 +1,5 @@
1
+ if Element && !Element.prototype.matches
2
+ proto = Element.prototype
3
+ proto.matches = proto.matchesSelector ||
4
+ proto.mozMatchesSelector || proto.msMatchesSelector ||
5
+ proto.oMatchesSelector || proto.webkitMatchesSelector
@@ -3,20 +3,45 @@ class Lanes.lib.Dom
3
3
  constructor: (el) ->
4
4
  @el = el
5
5
 
6
- qs: (selector) ->
6
+ qs: (selector, options = {}) ->
7
7
  el = @el.querySelector(selector)
8
- throw new TypeError("Unable to find element for selector #{selector}") unless el
9
- new Lanes.lib.Dom(el)
8
+ if not el and options.raise isnt false
9
+ throw new TypeError("Unable to find element for selector #{selector}")
10
+ new Lanes.lib.Dom(el || @el)
10
11
 
11
12
  qsa: (selector) ->
12
13
  @el.querySelectorAll(selector)
13
14
 
14
- wrap = (fn) ->
15
+ remove: ->
16
+ @el.parentElement.removeChild(@el)
17
+
18
+ focusAndSelect: ->
19
+ @el.select?()
20
+ @el.focus?()
21
+
22
+ closest: (selector) ->
23
+ # Traverse the DOM up with a while loop
24
+ el = @el
25
+ while el.nodeType isnt 9 and !el.matches(selector)
26
+ # Increment the loop to the parent node
27
+ el = el.parentNode
28
+ return null unless el
29
+ _.dom(el)
30
+
31
+ wrapArg = (fn) ->
15
32
  return ->
16
33
  fn(this.el, arguments...)
17
34
 
35
+ chain = (fn) ->
36
+ return ->
37
+ fn(this.el, arguments...)
38
+ return this
39
+
18
40
  for name, func of Lanes.Vendor.dom
19
- Lanes.lib.Dom::[name] = wrap(func)
41
+ Lanes.lib.Dom::[name] = if name.match(/^has/)
42
+ wrapArg
43
+ else
44
+ chain(func)
20
45
 
21
46
  Object.defineProperties(Lanes.lib.Dom.prototype, {
22
47
 
@@ -37,11 +62,15 @@ Object.defineProperties(Lanes.lib.Dom.prototype, {
37
62
 
38
63
 
39
64
  _.dom = (unknown, query) ->
40
- el = if _.isElement(unknown)
65
+ el = if _.isBlank(unknown)
66
+ throw new TypeError("Selector / DOM node is not present")
67
+ else if _.isElement(unknown)
41
68
  unknown
42
- else if _.isFunction(unknown.getDOMNode)
43
- unknown.getDOMNode()
44
- else
69
+ else if unknown.isReactComponent
70
+ Lanes.Vendor.ReactDOM.findDOMNode(unknown)
71
+ else if unknown.nodeType is 9 # body tag
72
+ unknown
73
+ else if unknown
45
74
  throw new TypeError("Unable to obtain dom reference to #{unknown}")
46
75
 
47
76
  if query
@@ -0,0 +1,11 @@
1
+ Lanes.u.format ||= {}
2
+
3
+ Lanes.u.format.shartDate = (d) ->
4
+ _.moment(d).format('L')
5
+
6
+ Lanes.u.format.shartDateTime = (d) ->
7
+ _.moment(d).format('lll')
8
+
9
+ Lanes.u.format.currency = (v) ->
10
+ v ||= '0'
11
+ _.sprintf('%0.2f', parseFloat(v)).replace(/\B(?=(\d{3})+\b)/g, ",")
@@ -6,7 +6,9 @@
6
6
  //= require ./loader
7
7
  //= require ./MakeBaseClass
8
8
  //= require ./el
9
+ //= require ./dom-polyfills
9
10
  //= require ./dom
11
+ //= require ./format
10
12
  //= require ./promise_helpers
11
13
  //= require ./results
12
14
  <% if Lanes.env.development?
@@ -0,0 +1,6 @@
1
+ Lanes.lib.HotReload =
2
+
3
+ remember: (klass) ->
4
+ return klass
5
+
6
+ Lanes.log.setDefaultLevel(Lanes.log.levels.INFO)
@@ -11,18 +11,24 @@ Lanes.warn = (msg...) ->
11
11
  else console.warn(msg...)
12
12
  null
13
13
 
14
- Lanes.log = (msg...) ->
15
- return unless console
16
- if msg[0] instanceof Error
17
- console.warn(msg[0].stack)
18
- else console.log(msg...)
19
- null
20
-
21
14
  distillTypes = (type, ns) ->
22
15
  _.reduce( type.split( '.' ), ( ( memo, val ) -> return if memo then memo[ val ] else null ), ns )
23
16
 
24
17
  Lanes.u = {
25
18
 
19
+ withReactContext: (newContext, fn) ->
20
+ previousContext = Lanes.Vendor.ReactContext.current
21
+ Lanes.Vendor.ReactContext.current = _.clone newContext
22
+ ret = fn()
23
+ Lanes.Vendor.ReactContext.current = previousContext
24
+ ret
25
+
26
+ makeComparatorUsing: (method) ->
27
+ (a, b) -> Lanes.u.comparator(a[method], b[method])
28
+
29
+ comparator: (a, b) ->
30
+ if a < b then 1 else if a > b then -1 else 0
31
+
26
32
  objectForPath: (path) ->
27
33
  parts = path.replace(/\.js$/, '').split('/')
28
34
  last = null
@@ -52,6 +58,17 @@ Lanes.u = {
52
58
  obj = _.reduce( parts, ( ( memo, val ) -> return if memo then memo[ val ] else null ), Lanes )
53
59
  obj?[name]
54
60
 
61
+ isModel: (object) ->
62
+ _.isObject(object) and object.isProxy or object instanceof Lanes.Models.BasicModel
63
+
64
+ isCollection: (object) ->
65
+ object instanceof Lanes.Models.Collection ||
66
+ object instanceof Lanes.Models.BasicCollection ||
67
+ object instanceof Lanes.Models.SubCollection
68
+
69
+ isState: (object) ->
70
+ _.isObject(object) and object.isProxy or object instanceof Lanes.Models.State
71
+
55
72
  # Can be called one of two ways:
56
73
  # With ns being a string, which will attempt to deref it then deref name inside it
57
74
  # or with ns being an object, which will dref name inside it
@@ -77,14 +94,12 @@ Lanes.u = {
77
94
  else
78
95
  method
79
96
 
80
- closestEl: (el, name) ->
81
- # Traverse the DOM up with a while loop
82
- while ! _.dom(el).hasClass(name)
83
- # Increment the loop to the parent node
84
- el = el.parentNode
85
- return null unless el
97
+ invokeOrReturn: (func, scope = this) ->
98
+ if _.isFunction(func)
99
+ func.apply(scope)
100
+ else
101
+ func
86
102
 
87
- return el
88
103
 
89
104
  }
90
105
 
@@ -105,12 +120,17 @@ Lanes.u = {
105
120
  lcDash = (char, match, index) ->
106
121
  return ( if index == 0 then '' else '_' ) + char.toLowerCase()
107
122
 
123
+ originalTitleize = _.titleize
124
+
108
125
  _.mixin({
109
126
  dasherize: (str) ->
110
127
  _.trim(str).replace(/([A-Z])/g, lcDash).replace(/[-_\s]+/g, '-').toLowerCase()
111
128
 
129
+ titleize: (str) ->
130
+ originalTitleize.call(_, _.humanize(str))
131
+
112
132
  field2title: (field) ->
113
- _.titleize _.humanize field
133
+ _.titleize field
114
134
 
115
135
  toSentence: (words = [], comma = ', ', nd = ' and ') ->
116
136
  last = words.pop()
@@ -121,5 +141,20 @@ _.mixin({
121
141
  last
122
142
  else
123
143
  ''
144
+ isPromise: (obj) ->
145
+ !!obj && (_.isObject(obj) || _.isFunction(obj)) && _.isFunction(obj.then)
146
+
147
+ isBlank: (value) ->
148
+ switch true
149
+ when _.isDate(value)
150
+ _.isNaN(value.getDate())
151
+ when _.isError(value), _.isNaN(value)
152
+ true
153
+ when _.isElement(value), _.isFunction(value), _.isBoolean(value), _.isRegExp(value)
154
+ false
155
+ when _.isNumber(value)
156
+ !value
157
+ else
158
+ _.isEmpty(value)
124
159
 
125
160
  })
@@ -1,7 +1,8 @@
1
1
  # ------------------------------------------------------------------ #
2
2
  # Handles Association definitions. #
3
3
  # It creates a derived definition for each one #
4
- # and contains utility functions to operate on them #
4
+ # Note! An AssociationMap is created for each type of Model, and #
5
+ # is shared between all instances #
5
6
  # ------------------------------------------------------------------ #
6
7
  class Lanes.Models.AssocationMap
7
8
  constructor: (@klass) ->
@@ -9,15 +10,38 @@ class Lanes.Models.AssocationMap
9
10
  @definitions = @klass::associations
10
11
  @definitions['created_by'] ||= { model: 'Lanes.Models.User', readOnly: true }
11
12
  @definitions['updated_by'] ||= { model: 'Lanes.Models.User', readOnly: true }
13
+ @collections = Object.create(null)
14
+ @proxy = Object.create(null)
12
15
  for name, options of @definitions
13
16
  @klass::derived[name] = this.derivedDefinition(name, options)
14
17
 
18
+ # finds the correct class for association
15
19
  getClassFor: (name) ->
16
20
  definition = @definitions[name]
17
21
  object = definition.model || definition.collection
18
22
  Lanes.u.findObject(object, 'Models', @klass::FILE)
19
23
 
20
- getOptions: (name, definition, model) ->
24
+ getProxyFor: (name) ->
25
+ @proxy[name] ||= (
26
+ Lanes.Models.AssocationProxy.construct( @getClassFor(name),
27
+ association_pk: @pk(name)
28
+ association_name: name
29
+ )
30
+ )
31
+
32
+ clear: (model) ->
33
+ for name, value of @proxy
34
+ Proxy = @getProxyFor(name)
35
+ model._cache[name] = new Proxy( this, this.getOptions(name, model) )
36
+
37
+ replace: (parent, name, model) ->
38
+ parent._cache[name] = model
39
+ model.parent = parent
40
+ parent.trigger("change", parent, {})
41
+ parent.trigger("change:#{name}", model, {})
42
+
43
+ getOptions: (name, model) ->
44
+ definition = @definitions[name]
21
45
  options = { parent: model }
22
46
  if definition.options
23
47
  _.extend(options, Lanes.u.resultsFor(model, definition.options))
@@ -25,35 +49,47 @@ class Lanes.Models.AssocationMap
25
49
 
26
50
  # will be called in the scope of the parent model
27
51
  createModel: (association, name, definition, fk, pk, target_class) ->
28
- target_class ||= association.getClassFor(name)
29
- options = association.getOptions(name, definition, this)
30
- model_id = this.get(pk)
31
- if model_id && model_id == this._cache[name]?.id
32
- this._cache[name]
52
+ if definition.autoCreate
53
+ target_class ||= association.getClassFor(name)
54
+ options = association.getOptions(name, this)
55
+ model_id = this.get(pk)
56
+ if model_id && model_id == this._cache[name]?.id
57
+ this._cache[name]
58
+ else
59
+ new target_class(options)
33
60
  else
34
- new target_class(options)
35
-
36
- # returns a collection for the given association.
37
- collectionFor: (name) ->
38
- klass = @getClassFor(name)
39
- if klass::isModel
40
- klass.Collection
41
- else
42
- klass
43
-
61
+ Proxy = association.getProxyFor(name)
62
+ new Proxy( association, association.getOptions(name, @) )
44
63
 
45
64
  # will be called in the scope of the parent model
46
65
  createCollection: (association, name, definition, fk, pk, target_class) ->
47
66
  target_class ||= association.getClassFor(name)
48
- options = association.getOptions(name, definition, this)
67
+ options = association.getOptions(name, this)
49
68
  options.filter ||= {}
50
69
  options.filter[fk] = this.get(pk)
70
+ options.inverse =
71
+ name: definition.inverse
72
+ without: name
51
73
 
52
- if target_class::isCollection
74
+ if true == target_class::isCollection
53
75
  new target_class(options.models || [], options)
54
76
  else
55
77
  options.model = target_class
56
- new Lanes.Models.AssociationCollection(options. models || [], options)
78
+ new Lanes.Models.AssociationCollection(options.models || [], options)
79
+
80
+ # returns a collection for the given association.
81
+ collectionFor: (name, model, options = {}) ->
82
+ options = _.extend({}, this.getOptions(name, model), options)
83
+ @collections[name] ||= (
84
+ Klass = @getClassFor(name)
85
+ if true == Klass::isModel
86
+ new Lanes.Models.AssociationCollection(options.models || [],
87
+ _.extend({}, options, model: Klass)
88
+ )
89
+ else
90
+ new Klass(options.models || [], options)
91
+ )
92
+
57
93
  # returns the definition for the derived property
58
94
  derivedDefinition: (name, definition) ->
59
95
  defaultCreator = if definition.model then this.createModel else this.createCollection
@@ -62,58 +98,98 @@ class Lanes.Models.AssocationMap
62
98
  -> definition.default.apply(this, args) || defaultCreator.apply(this, args)
63
99
  else
64
100
  defaultCreator
65
- { deps: [this.pk(name)], fn: _.partial(createFn, args...) }
66
-
101
+ { fn: _.partial(createFn, args...) }
67
102
 
68
103
  # Sets the assocations for "model"
69
- set: (model, data) ->
70
- this._set(model, data, 'set')
104
+ set: (model, data, options) ->
105
+ this._set(model, data, options, 'set')
71
106
  for name, value of data
72
- if @definitions[name] && value?.isModel && !value.isNew()
107
+ if @exists(name) && Lanes.u.isModel(value) && !value.isNew()
73
108
  model[@pk(name)] = if value then value.getId() else null
74
109
 
75
- setFromServer: (model, data) ->
76
- this._set(model, data, 'setFromServer')
110
+ setFromServer: (model, data, options) ->
111
+ this._set(model, data, options, 'setFromServer')
77
112
 
78
- _set: (model, data, fn_name) ->
113
+ onIdChange: (model) ->
114
+ for name, def of @definitions
115
+ if def.collection and @isCreated(model, name) and model[name]?.associationFilter
116
+ model[name]?.associationFilter[ @fk(name) ] = model[ @pk(name) ]
117
+
118
+ _set: (model, data, options, fn_name) ->
79
119
  for name, value of data
80
- continue unless @definitions[name]
120
+ # we're done if we're not setting the association to anything
121
+ # and it's not yet created
122
+ continue if not @exists(name) or
123
+ (_.isEmpty(value) and not @isCreated(model, name))
124
+
81
125
  association = model[name]
82
- unless _.isObject(value)
83
- association.clear()
84
- continue
85
- attributes = if _.isFunction(value.serialize) then value.serialize() else value
86
- association[fn_name]( attributes )
87
- # if we're replaceing the model's contents with another, copy the dirty status as well
88
- if association.isModel
89
- model.set(this.pk(name), association.id) unless association.isNew
90
- association.isDirty = value.isDirty if value.isModel
126
+
127
+ if association.isProxy and Lanes.u.isModel(value) and not value.isProxy
128
+ association.replaceWithModel(value, association_name: name)
129
+
130
+ else if Lanes.u.isModel(association)
131
+ continue if association is value
132
+
133
+ if !value
134
+ association.clear()
135
+ else
136
+ model.set(this.pk(name), value.id, options) if value.id
137
+ if Lanes.u.isModel(value)
138
+ @replace(model, name, value)
139
+ else
140
+ association[fn_name]( value )
141
+
142
+ if options?.silent isnt true and not association.isProxy
143
+ model.trigger("change:#{name}", value, {})
144
+ else
145
+ if value then association[fn_name]( value, options ) else association.clear()
91
146
 
92
147
  pk: (name) ->
93
148
  def = @definitions[name]
94
- return null unless name
95
- def.pk || ( if def.model then "#{name}_id" else "id" )
149
+ return null unless name and def
150
+ _.result(def, 'pk', ( if def.model then "#{name}_id" else "id" ) )
96
151
 
97
152
  fk: (name) ->
98
153
  def = @definitions[name]
99
- return null unless name
100
- def.fk || ( if def.model then "id" else "#{name}_id" )
154
+ return null unless name and def
155
+ _.result(def, 'fk', ( if def.model then "id" else "#{name}_id" ) )
101
156
 
102
157
  # returns the data from all assocations for saving
103
158
  dataForSave: (model, options) ->
104
159
  ret = {}
105
160
  options.saveDepth = ( if options.saveDepth then options.saveDepth + 1 else 1 )
106
161
  return ret if options.saveDepth > 5
107
- for name, options of @definitions
108
- break if options.readOnly
162
+ for name, def_options of @definitions when @isCreated(model, name)
163
+ continue if def_options.readOnly or
164
+ (options.onlyAssociations and not _.include(options.onlyAssociations, name))
109
165
  assoc = model[name]
110
- ret[name] = assoc.dataForSave(options) if _.result(assoc, 'isDirty')
166
+ ret[name] = assoc.dataForSave(
167
+ _.extend({}, options, def_options)
168
+ ) if _.result(assoc, 'isDirty')
169
+ ret
170
+
171
+ serialize: (model, options = {depth: 1}) ->
172
+ ret = {}
173
+ options.depth ||= 1
174
+ return ret if options.depth > 5
175
+ for name, opts of @definitions
176
+ if @isCreated(model, name) and name isnt 'parent'
177
+ ret[name] = model[name].serialize(options)
111
178
  ret
112
179
 
113
180
  # return a list of assocations from "name" that are not loaded
114
181
  nonLoaded: (model, names) ->
115
182
  list = []
116
183
  for name in names
117
- if _.has(@definitions, name) && model[name].isNew()
184
+ if @exists(name) &&
185
+ (Lanes.u.isCollection(model[name]) ||
186
+ model[name].isProxy ||
187
+ model[name].isNew())
118
188
  list.push(name)
119
189
  list
190
+
191
+ exists: (name) ->
192
+ _.has(@definitions, name)
193
+
194
+ isCreated: (model, name) ->
195
+ !!(@exists(name) and model._cache[name])