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
@@ -0,0 +1,71 @@
1
+ class Lanes.Models.Query.CollectionResult extends Lanes.Models.Query.Result
2
+
3
+ constructor: (@query) ->
4
+ @collection.on('add remove reset', =>
5
+ @query.trigger('change', @query)
6
+ )
7
+ @collection.on('sort', =>
8
+ @query.changeCount += 1
9
+ )
10
+
11
+ this
12
+
13
+ rowAt: (index, options = {}) ->
14
+ model = @collection.at(index)
15
+ for field, i in @query.fields.models
16
+ model[field.id]
17
+
18
+ allRows: (options) ->
19
+ rows = (@rowAt(i, options) for i in [0...@length])
20
+ _.Promise.resolve(rows)
21
+
22
+ modelAt: (index) ->
23
+ @collection.at(index)
24
+
25
+ saveModelChanges: (model, index) ->
26
+ old = @collection.at(index)
27
+ @collection.remove(old)
28
+ @collection.add(model, at:index)
29
+ @query.changeCount++
30
+
31
+ addBlankRow: (index) ->
32
+ @collection.add({}, at: index)
33
+
34
+ removeRow: (index = 0) ->
35
+ @collection.remove(
36
+ @collection.at(index)
37
+ )
38
+
39
+ reload: ->
40
+ @collection.reload().then(@)
41
+
42
+ ensureLoaded: ->
43
+ @collection.ensureLoaded().then(@)
44
+
45
+ reset: Lanes.emptyFn
46
+
47
+ rowRepresentation: (rowNum) ->
48
+ @modelAt(rowNum)
49
+
50
+ valueForField: (rowNum, field) ->
51
+ @modelAt(rowNum)[field.id]
52
+
53
+ fieldToSortValue:
54
+ any: (v) -> v
55
+ bigdec: (v) -> parseFloat(v)
56
+
57
+ _updateSort: ->
58
+ field = @query.sortField
59
+ asc = @query.sortAscending
60
+ f2v = @fieldToSortValue[field.type] || @fieldToSortValue.any
61
+ @collection.comparator = field.sortBy or (a, b) ->
62
+ a = f2v(a[field.id]); b = f2v(b[field.id])
63
+ result = if a < b then -1 else if a > b then 1 else 0
64
+ if asc then result else result * -1
65
+ @collection.sort()
66
+
67
+ Object.defineProperties Lanes.Models.Query.CollectionResult.prototype,
68
+ length:
69
+ get: -> @query.src.length
70
+ collection:
71
+ get: -> @query.src
@@ -0,0 +1,9 @@
1
+ class Lanes.Models.Query.Result
2
+
3
+ @extend: (other) ->
4
+ _.extend(other.prototype, this.prototype)
5
+
6
+ sortingFunction: ->
7
+ field = @query.sortField
8
+ return false unless field
9
+ if _.isFunction field.sortBy then field.sortBy else false
@@ -1,7 +1,7 @@
1
1
  createHelper = (component, name) ->
2
2
  unless component.prototype[name]
3
3
  Object.defineProperty(component.prototype, name,
4
- configurable: true, enumerable: false
4
+ configurable: true, enumerable: true
5
5
  get: -> @data?.states[name]
6
6
  set: (val) ->
7
7
  @data?.rebind("#{name}": val)
@@ -25,7 +25,11 @@ Lanes.React.Component = {
25
25
  klass::mixins = _.unique(klass::mixins.concat(mixins))
26
26
  comp = React.createClass(klass.prototype)
27
27
  extendComponent(comp)
28
- Lanes.lib.HotReload?.rememberReact(comp)
29
- comp
28
+ return Lanes.lib.HotReload.remember(comp)
29
+ }
30
30
 
31
+ Lanes.React.BaseComponent = {
32
+ extend: (klass, mixins = @defaultMixins) ->
33
+ comp = React.createClass(klass.prototype)
34
+ return Lanes.lib.HotReload.remember(comp)
31
35
  }
@@ -4,23 +4,23 @@ class Lanes.Views.PubSub extends Lanes.Views.ModelObserver
4
4
  modelEvents:
5
5
  'remote-update': 'onChange'
6
6
 
7
- hideUpdate: (field)->
8
- Lanes.dom.removeClass(field,"updated")
7
+ hideUpdate: (field) ->
8
+ Lanes.dom.removeClass(field, "updated")
9
9
 
10
- showUpdate: (field)->
11
- Lanes.dom.addClass(field,"updated")
10
+ showUpdate: (field) ->
11
+ Lanes.dom.addClass(field, "updated")
12
12
  _.delay(@hideUpdate, 3000, field )
13
13
 
14
- onChange: (model,change)->
14
+ onChange: (model, change) ->
15
15
  return unless change.record == this.getModel()
16
16
  for field in change.fields
17
17
  this.showUpdate(field) if field = @view.query("[name=#{field}]")
18
18
 
19
- bindModel: (model)->
19
+ bindModel: (model) ->
20
20
  Lanes.Models.PubSub.add(model)
21
21
  super
22
22
 
23
- unBindModel: (model)->
23
+ unBindModel: (model) ->
24
24
  Lanes.Models.PubSub.remove(model)
25
25
  super
26
26
 
@@ -5,10 +5,7 @@ Lanes.React.Root = React.createClass
5
5
  getChildContext: ->
6
6
  viewport: @props.viewport
7
7
 
8
- propTypes:
9
- viewport: Lanes.PropTypes.State.isRequired
10
-
11
8
  render: ->
12
9
  <div classNames="root">
13
- <Lanes.React.Router.RouteHandler/>
10
+ {this.props.children}
14
11
  </div>
@@ -4,6 +4,7 @@ Lanes.React.Screen = {
4
4
  Lanes.React.Mixins.Data
5
5
  Lanes.React.Mixins.Viewport
6
6
  Lanes.React.Mixins.Screen
7
+ Lanes.React.Mixins.Access
7
8
  Lanes.React.Mixins.RelayEditingState
8
9
  ]
9
10
 
@@ -7,15 +7,15 @@ checkerFor = (name, checker, isRequired) ->
7
7
 
8
8
  checkerFor 'Model', (props, propName, componentName) ->
9
9
  val = props[propName]
10
- if val and (!_.isObject(val) or !val.isModel)
10
+ if val and (!_.isObject(val) or not Lanes.u.isModel(val))
11
11
  return new Error("#{propName} is not a Lanes Model")
12
12
 
13
13
  checkerFor 'State', (props, propName, componentName) ->
14
14
  val = props[propName]
15
- if val and (!_.isObject(val) or !val.isState)
15
+ if val and (!_.isObject(val) or not Lanes.u.isState(val))
16
16
  return new Error("#{propName} is not a state object")
17
17
 
18
18
  checkerFor 'Collection', (props, propName, componentName) ->
19
19
  val = props[propName]
20
- if val and (!_.isObject(val) or !val.isCollection)
20
+ if val and (!_.isObject(val) or not Lanes.u.isCollection(val))
21
21
  return new Error("#{propName} is not a Lanes Collection")
@@ -3,28 +3,62 @@ ALL_INSTANCES = []
3
3
  class Lanes.React.Viewport extends Lanes.Models.State
4
4
 
5
5
  @all: -> ALL_INSTANCES
6
+ @displayError: (msg) -> _.first(ALL_INSTANCES)?.displayError(msg)
6
7
 
7
8
  session:
8
9
  width: 'number'
9
10
  height: 'number'
10
11
  el: 'element'
11
12
  selector: 'string'
12
- root: 'element'
13
+ domRoot: 'element'
14
+ reactRoot: 'object'
15
+ lanes: 'element'
16
+ modalProps: 'object'
13
17
 
14
18
  constructor: ->
15
19
  super
16
20
  ALL_INSTANCES.push(this)
17
- root = document.body.querySelector(@selector)
21
+ return unless @selector
22
+ @domRoot = document.body.querySelector(@selector)
23
+ _.dom(@domRoot).addClass('lanes-root')
18
24
  Lanes.fatal("Root selector #{@selector} not found") unless root
19
- _.dom(root).html = "<div class='lanes'/>"
20
- Lanes.lib.ResizeSensor(root, _.debounce( =>
25
+ _.dom(@domRoot).html = "<div class='lanes'/>"
26
+ this.lanes = @domRoot.querySelector('.lanes')
27
+ Lanes.lib.ResizeSensor(@domRoot, _.debounce( =>
21
28
  @_updateDimensions()
22
29
  , 250))
23
- this.root = root.querySelector('.lanes')
24
30
  this._updateDimensions()
25
31
 
32
+ onBoot: ->
33
+ prev = _.dom(this.domRoot.previousElementSibling)
34
+ prev.addClass('complete') if prev.hasClass('loading')
35
+ _.delay(->
36
+ prev.remove()
37
+ , 100)
26
38
 
27
39
  _updateDimensions: ->
28
40
  this.set
29
- width: this.root.clientWidth
30
- height: this.root.clientHeight
41
+ width: @lanes.clientWidth
42
+ height: @lanes.clientHeight
43
+
44
+
45
+ displayError: (msg) ->
46
+ @modalProps = {
47
+ show: true, buttons: ['OK'], title: 'Error',
48
+ body: -> React.createElement('h3', {}, msg)
49
+ }
50
+
51
+ hideModal: ->
52
+ @modalProps = {show: false}
53
+
54
+ displayModal: (props) ->
55
+ @modalProps = _.extend(props, show: true)
56
+
57
+ renderRoot: ->
58
+ cntrl = Lanes.Extensions.controlling()
59
+ component = cntrl?.rootComponent?(this) ||
60
+ Lanes.React.Root.DefaultComponentNotFound
61
+ root = React.createElement(Lanes.React.Root, {viewport: @},
62
+ React.createElement(component)
63
+ )
64
+ @reactRoot = Lanes.Vendor.ReactDOM.render(root, @lanes)
@@ -5,4 +5,3 @@
5
5
  //= require ./Screen
6
6
  //= require ./Root
7
7
  //= require ./DefaultComponentNotFound
8
- //= require ./Router
@@ -1,5 +1,8 @@
1
1
  calculateAccess = (comp, props) ->
2
- model = comp[comp.modelForAccess || 'model']
2
+
3
+ model = _.result(comp, 'modelForAccess') ||
4
+ comp.commands?.getModel()?.modelForAccess() ||
5
+ comp.model?.modelForAccess()
3
6
 
4
7
  accessRight = if props.readonly or comp.context?.readonly
5
8
  'r'
@@ -12,32 +12,39 @@ class DataWrapper
12
12
  @rebind(_.clone(initialState), silent: true)
13
13
 
14
14
  rebind: (objects, options = {}) ->
15
- customEvents = _.result(@component, 'bindDataEvents') || {}
15
+ customEvents = _.result(@component, 'bindDataEvents', {})
16
16
  for name, state of objects
17
+ if false == state
18
+ continue
17
19
  unless state
18
20
  Lanes.warn "#{name} is not set on #{@componentName()}"
19
21
  continue
20
22
  prevState = @states[name]
23
+ # onto next if the object is the same
24
+ continue if prevState == state
25
+
21
26
  @states[name] = state
22
27
  this.stopListening(prevState) if prevState
23
28
 
24
29
  this.bindEvents(name, state, customEvents[name]) if state
25
30
 
26
- if state.isModel and not ( false == @component.pubsub or false == @component?.pubsub?[name] )
27
-
28
- Lanes.Models.PubSub.remove(prevState) if prevState
29
- Lanes.Models.PubSub.add(state)
30
-
31
- @listenTo(state, 'remote-update', @onPubSubChangeSet)
32
- @listenToNetworkEvents() if state.listenNetworkEvents
33
-
34
-
31
+ if Lanes.u.isModel(state)
32
+ @listenToNetworkEvents(state) if @component.listenNetworkEvents
33
+ unless false == @component.pubsub or false == @component?.pubsub?[name]
34
+ if !prevState? or prevState.getId() != state.getId()
35
+ Lanes.Models.PubSub.remove(prevState) if prevState
36
+ unless false == state.pubsub
37
+ if state.isNew()
38
+ state.once "change:#{state.idAttribute}", -> Lanes.Models.PubSub.add(state)
39
+ else
40
+ Lanes.Models.PubSub.add(state)
41
+ @listenTo(state, 'remote-update', @onPubSubChangeSet)
35
42
  this.setComponentState({}) unless _.isEmpty(objects) or options.silent
36
43
 
37
- listenToNetworkEvents: ->
38
- @listenTo(collection, 'error', @onError)
39
- .listenTo(collection, 'request', @onRequest)
40
- .listenTo(collection, 'sync', @onSync)
44
+ listenToNetworkEvents: (state) ->
45
+ @listenTo(state, 'error', @onError)
46
+ .listenTo(state, 'request', @onRequest)
47
+ .listenTo(state, 'load sync', @onSync)
41
48
 
42
49
  onPubSubChangeSet: (model, cs) ->
43
50
  screen = @component.context?.screen || @component.getChildContext?()?.screen
@@ -46,14 +53,21 @@ class DataWrapper
46
53
  componentName: ->
47
54
  @component.constructor.displayName
48
55
 
56
+ onProxyReplace: (name, model) ->
57
+ @states[name] = model
58
+ @setComponentState(name, model)
59
+
49
60
  bindEvents: (name, state, events) ->
61
+ if state.isProxy
62
+ @listenTo(state, 'proxyreplace', _.partial(@onProxyReplace, name))
50
63
  if !events
51
- if state.isState
64
+ if state.isState or state.isProxy
52
65
  events ||= 'change'
53
- else if state.isCollection
66
+ else if Lanes.u.isCollection(state)
54
67
  events ||= 'add remove change sort reset'
55
68
  else
56
69
  Lanes.warn "Unable to listen to unknown type #{name}"
70
+
57
71
  @listenTo(state, events, _.partial(@setComponentState, name, state))
58
72
 
59
73
  onError: (modelOrCollection, options) ->
@@ -61,21 +75,21 @@ class DataWrapper
61
75
  unless options.silent
62
76
  @setComponentState
63
77
  isRequesting: false
64
- hasError: true
78
+ hasError: modelOrCollection?.errorMessage or true
65
79
  error: modelOrCollection.errors
66
80
 
67
81
  onInvalid: (model, res, options) ->
68
82
  @setComponentState(isInvalid: true) unless options.silent
69
83
 
70
- onRequest: (modelOrCollection, options) ->
84
+ onRequest: (modelOrCollection, type, options) ->
71
85
  # Set `state` only if there's no silent option
72
86
  unless options.silent
73
87
  @setComponentState
74
- isRequesting: true
88
+ isRequesting: type
75
89
  hasError: false
76
90
  isInvalid: false
77
91
 
78
- onSync: (modelOrCollection, res, options) ->
92
+ onSync: (modelOrCollection, res, options = {}) ->
79
93
  # Calls `setReactState` only if there's no silent option
80
94
  this.setComponentState(isRequesting: false) unless options.silent
81
95
 
@@ -90,7 +104,7 @@ class DataWrapper
90
104
 
91
105
  destroy: (state, events, fn) ->
92
106
  for name, state of @states
93
- Lanes.Models.PubSub.remove(state) if state?.isModel
107
+ Lanes.Models.PubSub.remove(state) if Lanes.u.isModel(state)
94
108
  this.stopListening()
95
109
  delete @component.data
96
110
 
@@ -98,11 +112,12 @@ class DataWrapper
98
112
  _.extend(DataWrapper.prototype, Lanes.Vendor.BBEvents)
99
113
 
100
114
  readDataObjects = (comp, newProps) ->
101
- bound = _.result(comp, 'dataObjects') || {}
102
- bound.model = 'props' if comp.props.model
103
- bound.collection = 'props' if comp.props.collection
115
+ bound = _.clone _.result(comp, 'dataObjects') || {}
116
+ bound.model ||= 'props' if comp.props.model
117
+ bound.collection ||= 'props' if comp.props.collection
104
118
  _.mapValues(bound, (value, name) ->
105
- if _.isFunction(value) then value.call(comp)
119
+ if _.isFunction(value)
120
+ if _.isEmpty(comp.data?.states[name]) then value.call(comp) else false
106
121
  else if 'props' == value then newProps?[name] or @props[name]
107
122
  else value
108
123
  , comp)
@@ -0,0 +1,27 @@
1
+ Lanes.React.Mixins.FieldErrors = {
2
+
3
+ mixins: [
4
+ Lanes.React.Mixins.ReadEditingState
5
+ ]
6
+
7
+ componentWillMount: ->
8
+ @getInvalidModel()?.maskInvalidFields()
9
+
10
+ getInvalidFieldName: ->
11
+ @props.validity_attribute || @props.name
12
+
13
+ getInvalidModel: ->
14
+ @props.model || _.first _.values @data?.states
15
+
16
+ isFieldValueInvalid: ->
17
+ !!@fieldInvalidValueMessage()
18
+
19
+ fieldInvalidValueMessage: ->
20
+ return '' unless @isEditingRecord()
21
+ @getInvalidModel()?.invalidMessageFor(
22
+ @getInvalidFieldName()
23
+ )
24
+
25
+ onFieldInteraction: ->
26
+ @getInvalidModel()?.unmaskInvalidField( @getInvalidFieldName() )
27
+ }
@@ -14,4 +14,8 @@ Lanes.React.Mixins.RelayEditingState = {
14
14
  if @props.writable?
15
15
  context.writable = @props.writable
16
16
  context
17
+
18
+ setModelUrl: (model) ->
19
+ @props.screen.model = model
20
+
17
21
  }
@@ -1,7 +1,21 @@
1
1
  Lanes.React.Mixins.Screen = {
2
+
2
3
  childContextTypes:
3
4
  screen: React.PropTypes.object
4
5
 
5
6
  listenNetworkEvents: true
6
7
 
8
+ loadOrCreateModel: (options) ->
9
+ if options.prop and @props[options.prop]
10
+ if options.syncOptions?.include
11
+ @props[options.prop].withAssociations(options.syncOptions.include, options.syncOptions)
12
+ @props[options.prop]
13
+ else
14
+ model = new options.klass
15
+ if options.attribute and @props.args?.length
16
+ model.fetch(_.extend( {}, options.syncOptions, {
17
+ query: {"#{options.attribute}": @props.args[0]}
18
+ })).then => @state?.commands?.setModel(model)
19
+ model
20
+
7
21
  }