lanes 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (104) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -0
  3. data/client/lanes/Config.coffee +1 -1
  4. data/client/lanes/access/LoginDialog.cjsx +1 -1
  5. data/client/lanes/access/Roles.coffee +1 -1
  6. data/client/lanes/access/User.coffee +2 -2
  7. data/client/lanes/access/screens/user-management/UserManagement.cjsx +1 -1
  8. data/client/lanes/components/calendar/styles.scss +1 -1
  9. data/client/lanes/components/grid/Body.cjsx +5 -2
  10. data/client/lanes/components/grid/EditingMixin.cjsx +3 -0
  11. data/client/lanes/components/grid/Editor.cjsx +3 -11
  12. data/client/lanes/components/grid/Grid.cjsx +22 -12
  13. data/client/lanes/components/grid/Selections.cjsx +4 -1
  14. data/client/lanes/components/grid/Toolbar.cjsx +1 -1
  15. data/client/lanes/components/record-finder/RecordFinder.cjsx +2 -2
  16. data/client/lanes/components/select-field/SelectField.cjsx +19 -16
  17. data/client/lanes/components/select-field/styles.scss +1 -1
  18. data/client/lanes/components/shared/FieldMixin.cjsx +2 -2
  19. data/client/lanes/components/shared/Input.cjsx +2 -13
  20. data/client/lanes/components/shared/InputFieldMixin.cjsx +15 -8
  21. data/client/lanes/components/shared/NetworkActivityOverlay.cjsx +1 -1
  22. data/client/lanes/components/shared/NumberInput.cjsx +4 -12
  23. data/client/lanes/components/shared/ToggleField.cjsx +0 -2
  24. data/client/lanes/components/shared/fields.scss +9 -0
  25. data/client/lanes/components/shared/styles.scss +2 -1
  26. data/client/lanes/components/toolbar/Toolbar.cjsx +1 -1
  27. data/client/lanes/lib/HotReload.coffee +2 -2
  28. data/client/lanes/lib/development.coffee +1 -1
  29. data/client/lanes/lib/loader.coffee +3 -3
  30. data/client/lanes/models/AssociationMap.coffee +1 -1
  31. data/client/lanes/models/AssociationProxy.coffee +1 -0
  32. data/client/lanes/models/Base.coffee +7 -10
  33. data/client/lanes/models/Collection.coffee +3 -6
  34. data/client/lanes/models/JobStatus.coffee +1 -1
  35. data/client/lanes/models/PubSub.coffee +51 -33
  36. data/client/lanes/models/Query.coffee +1 -1
  37. data/client/lanes/models/Sync.coffee +1 -1
  38. data/client/lanes/models/User.coffee +3 -3
  39. data/client/lanes/models/mixins/FileSupport.coffee +3 -3
  40. data/client/lanes/models/query/ArrayResult.coffee +3 -6
  41. data/client/lanes/models/query/CollectionResult.coffee +5 -3
  42. data/client/lanes/react/Component.coffee +2 -2
  43. data/client/lanes/react/DefaultComponentNotFound.cjsx +2 -2
  44. data/client/lanes/react/Screen.coffee +1 -1
  45. data/client/lanes/react/Viewport.coffee +1 -1
  46. data/client/lanes/react/mixins/Access.coffee +1 -1
  47. data/client/lanes/react/mixins/Data.coffee +9 -5
  48. data/client/lanes/screens/Commands.coffee +1 -1
  49. data/client/lanes/screens/UserPreferences.cjsx +1 -1
  50. data/client/lanes/testing/BeforeEach.coffee +7 -0
  51. data/client/lanes/vendor/base.js.erb +5 -0
  52. data/client/lanes/vendor/calendar.js.erb +5 -0
  53. data/client/lanes/vendor/commons.js.erb +5 -0
  54. data/client/lanes/vendor/{base.js → development/base.js} +37776 -40850
  55. data/client/lanes/vendor/development/calendar.js +1667 -0
  56. data/client/lanes/vendor/development/commons.js +39085 -0
  57. data/client/lanes/vendor/development/helpers.js +578 -0
  58. data/client/lanes/vendor/{toggle.js → development/toggle.js} +22 -82
  59. data/client/lanes/vendor/development/widgets.js +8975 -0
  60. data/client/lanes/vendor/production/base.js +63239 -0
  61. data/client/lanes/vendor/production/calendar.js +1667 -0
  62. data/client/lanes/vendor/production/commons.js +38505 -0
  63. data/client/lanes/vendor/production/toggle.js +285 -0
  64. data/client/lanes/vendor/production/widgets.js +8975 -0
  65. data/client/lanes/vendor/{calendar.scss → styles/calendar.scss} +6 -0
  66. data/client/lanes/vendor/{toggle.scss → styles/toggle.scss} +0 -0
  67. data/client/lanes/vendor/{widgets.scss → styles/widgets.scss} +2 -2
  68. data/client/lanes/vendor/toggle.js.erb +5 -0
  69. data/client/lanes/vendor/widgets.js.erb +5 -0
  70. data/lib/lanes/api/default_routes.rb +3 -3
  71. data/lib/lanes/api/routing.rb +1 -1
  72. data/lib/lanes/configuration.rb +8 -14
  73. data/lib/lanes/environment.rb +3 -0
  74. data/lib/lanes/extension/definition.rb +4 -0
  75. data/lib/lanes/system_settings.rb +21 -6
  76. data/lib/lanes/version.rb +1 -1
  77. data/npm-build/base.js +9 -4
  78. data/npm-build/build +9 -0
  79. data/npm-build/development.js +3 -1
  80. data/npm-build/package.json +34 -34
  81. data/npm-build/update-dayz +1 -1
  82. data/npm-build/webpack.config.js +36 -20
  83. data/spec/command-reference-files/initial/Gemfile +1 -1
  84. data/spec/command-reference-files/screen/config/screens.rb +1 -1
  85. data/spec/lanes/components/grid/RowEditorSpec.coffee +3 -1
  86. data/spec/lanes/components/select-field/SelectFieldSpec.coffee +33 -28
  87. data/spec/lanes/models/AssociationProxySpec.coffee +36 -37
  88. data/spec/lanes/models/BaseSpec.coffee +0 -32
  89. data/spec/lanes/models/CollectionSpec.coffee +0 -10
  90. data/spec/lanes/models/PubSubSpec.coffee +63 -13
  91. data/spec/lanes/screens/DefinitionsSpec.coffee +2 -2
  92. metadata +23 -20
  93. data/client/lanes/vendor/calendar.js +0 -17301
  94. data/client/lanes/vendor/commons.js +0 -19722
  95. data/client/lanes/vendor/development.js +0 -5471
  96. data/client/lanes/vendor/grid.js +0 -15384
  97. data/client/lanes/vendor/grid.scss +0 -928
  98. data/client/lanes/vendor/rw-widgets.eot +0 -0
  99. data/client/lanes/vendor/rw-widgets.svg +0 -18
  100. data/client/lanes/vendor/rw-widgets.ttf +0 -0
  101. data/client/lanes/vendor/rw-widgets.woff +0 -0
  102. data/client/lanes/vendor/widgets.js +0 -23204
  103. data/npm-build/compile.coffee +0 -19
  104. data/spec/lanes/models/ServerCacheSpec.coffee +0 -65
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 0bef7dd4d1ad62c9921002f1316cd341936b76fa
4
- data.tar.gz: 5fbe57c48a6c3c55228985871247a840ab385b40
3
+ metadata.gz: 4672ec1ecf5544a9da08b8eb826b5e573987ac7d
4
+ data.tar.gz: 53fb32ae3e09dec506b5cb9e1a961444c61bb122
5
5
  SHA512:
6
- metadata.gz: a3ded106dcb9b1569a36f1d744194af7027d1a441e74292aaf41b726f361fd94651eda041b3de921b0ada3662e8287364dc467a1487fbc67088a4d7588343667
7
- data.tar.gz: 24ac1aa4769187583415eeee331225480ce4315decaf080964d2b0d6c78809fb329e957ab4304afd31a387d6b922b05bb92c9da0f5ab044a4d143929fca8fcb9
6
+ metadata.gz: a8a6599cce4d9aaa1e0bcea8969636d7d83ecbd6263e4d6a325743af0531287ce74dee0b6fb69577b6607906114fbe4483bf1516be174f3a767279fa53ac65e8
7
+ data.tar.gz: f5e2136c4240d70c59c7ab485879e075d3600b0f4336e1b7da185823b4bdbcabaddae9abc38361f53b803c8fb4074583500b718df1f1e01db0eecaa6df1b975e
data/.gitignore CHANGED
@@ -18,3 +18,5 @@ test/version_tmp
18
18
  npm-build/node_modules
19
19
  tmp
20
20
  db/schema*
21
+ client/lanes/vendor/development/calendar.scss
22
+ client/lanes/vendor/production/calendar.scss
@@ -8,7 +8,7 @@ class SystemSettings extends Lanes.Models.Base
8
8
  settings: "object"
9
9
 
10
10
  modelTypeIdentifier: -> 'system-settings'
11
- url: -> Lanes.config.api_path + 'system-settings'
11
+ url: -> Lanes.config.api_path + '/system-settings'
12
12
  initialize: ->
13
13
  @on('change:settings', @setDefaultSettings)
14
14
  @setDefaultSettings()
@@ -1,5 +1,5 @@
1
1
  class Session extends Lanes.Models.Base
2
- api_path: 'lanes-access/user-session'
2
+ api_path: '/lanes-access/user-session'
3
3
 
4
4
  props:
5
5
  id: 'integer'
@@ -66,7 +66,7 @@ class Lanes.Models.UserRoleSet
66
66
  return this.testModelAccess(method, model)
67
67
 
68
68
  testModelAccess:(method, model) ->
69
- !!_.detect( @roles, (role) -> role.can(method, model) )
69
+ !!_.find( @roles, (role) -> role.can(method, model) )
70
70
 
71
71
  canRead:(model, field) ->
72
72
  this.can('read', model, field)
@@ -4,7 +4,7 @@ class Lanes.Models.User extends Lanes.Models.Base
4
4
  super
5
5
  this.access_data = access
6
6
 
7
- api_path: -> 'lanes-access/users'
7
+ api_path: -> '/lanes-access/users'
8
8
  derived:
9
9
  roles:
10
10
  deps: ['role_names', 'access_data']
@@ -64,7 +64,7 @@ class Lanes.Models.User extends Lanes.Models.Base
64
64
 
65
65
 
66
66
  class Session extends Lanes.Models.Base
67
- api_path: 'lanes-access/user-session'
67
+ api_path: '/lanes-access/user-session'
68
68
  props:
69
69
  id: 'integer'
70
70
  login: 'string'
@@ -11,7 +11,7 @@ class Lanes.Access.Screens.UserManagement extends Lanes.React.Screen
11
11
  _.map user.role_names, (rn) -> {id: rn, name: _.titleize(rn) }
12
12
 
13
13
  setRolesForUser: (roles, options) ->
14
- options.model.role_names = _.pluck(roles, 'id')
14
+ options.model.role_names = _.map(roles, 'id')
15
15
 
16
16
  editors: (props) ->
17
17
  role_names: ({model}) =>
@@ -1,3 +1,3 @@
1
1
  $dayz-event-colors: $lanes-color-selections;
2
2
  $dayz-event-text-colors: $lanes-text-color-selections;
3
- @import "lanes/vendor/calendar";
3
+ @import "lanes/vendor/styles/calendar";
@@ -15,7 +15,10 @@ class Lanes.Components.Grid.Body extends Lanes.React.BaseComponent
15
15
  )
16
16
  left = ev.clientX - ourBounds.left
17
17
  selectedIndex = (if @props.selectedIndex == index then null else index)
18
- selectedModel = if selectedIndex? then @props.query.results.modelAt(selectedIndex)?.clone() else null
18
+
19
+ selectedModel = if selectedIndex?
20
+ @props.query.results.modelAt(selectedIndex, clone: true)
21
+ else null
19
22
  @props.onRowClick(selectedModel, selectedIndex,
20
23
  {top, left, container: ourBounds, rowHeight: clickBounds.height}
21
24
  )
@@ -69,8 +72,8 @@ class Lanes.Components.Grid.Body extends Lanes.React.BaseComponent
69
72
 
70
73
  <Lanes.Components.Grid.Editor
71
74
  {...@props}
72
-
73
75
  cellStyles={@props.cellStyles}
76
+ onSave={@props.onEditSave}
74
77
  onCancel={@props.onEditCancel}
75
78
  editing={@props.editing} />
76
79
 
@@ -13,6 +13,7 @@ Lanes.Components.Grid.EditingMixin = {
13
13
  syncImmediatly: React.PropTypes.oneOfType([
14
14
  React.PropTypes.bool, React.PropTypes.func
15
15
  ])
16
+
16
17
  editorTypes:
17
18
  text: (props) ->
18
19
  <input type="text" {...props}
@@ -31,6 +32,8 @@ Lanes.Components.Grid.EditingMixin = {
31
32
 
32
33
  listenNetworkEvents: true
33
34
  getDefaultProps: -> editors: {}
35
+ componentDidMount: ->
36
+ _.dom(@).qs('input').focusAndSelect()
34
37
 
35
38
  renderControls: ->
36
39
  if @props.allowDelete
@@ -11,21 +11,13 @@ class Lanes.Components.Grid.Editor extends Lanes.React.BaseComponent
11
11
 
12
12
  onEditSave: (model, isDeleted = false) ->
13
13
  if (isDeleted)
14
- @props.query.results.removeRow(@state.selectedIndex)
14
+ @props.query.results.removeRow(@props.editing.index)
15
15
  else
16
- @props.query.results.saveModelChanges(model, @state.selectedIndex)
17
- this.hideEditor()
18
-
19
- componentWillReceiveProps: (nextProps) ->
20
- if nextProps.editingRowIndex?
21
- @setState(
22
- selectedIndex: nextProps.editingRowIndex
23
- selectedModel: @props.query.results.modelAt(nextProps.editingRowIndex)?.clone()
24
- )
16
+ @props.query.results.saveModelChanges(model, @props.editing.index)
17
+ @props.onSave()
25
18
 
26
19
  render: ->
27
20
  return null unless @props.editing
28
-
29
21
  Editor = if true == @props.editor
30
22
  Lanes.Components.Grid.RowEditor
31
23
  else
@@ -58,21 +58,17 @@ class Lanes.Components.Grid extends Lanes.React.Component
58
58
 
59
59
  @setState(sortInfo: sortInfo, selectedIndex: undefined, selectedModel: undefined)
60
60
 
61
- startEdit: (editingRowIndex = 0) ->
62
- @setState({editingRowIndex})
63
- _.defer => @setState({editingRowIndex: null})
64
-
65
- cancelEdit: ->
66
- if @state.editing?.model.isNew()
67
- @props.query.results.removeRow(@state.editing.index)
68
- @setState(editing: null)
69
-
70
- onRowClick: (selectedModel, selectedIndex, position) ->
61
+ startEdit: (index, options = {}) ->
62
+ editing = _.extend({}, options, {
63
+ index: index,
64
+ model: options.model or @props.query.results.modelAt(index)
65
+ position: options.position or (index * 50)
66
+ })
71
67
  set = (attrs = {}) =>
72
68
  if @props.editor and false isnt @props.commands?.isEditing()
73
- @setState(_.extend(attrs, editing: {index: selectedIndex, model: selectedModel, position}))
69
+ @setState( _.extend({}, attrs, {editing}) )
74
70
  if @props.onSelectionChange
75
- osc = @props.onSelectionChange(selectedModel, selectedIndex)
71
+ osc = @props.onSelectionChange(editing.model, editing.index)
76
72
  if _.isPromise(osc)
77
73
  @setState(is_loading: true)
78
74
  osc.then -> set(is_loading: false)
@@ -81,14 +77,28 @@ class Lanes.Components.Grid extends Lanes.React.Component
81
77
  else
82
78
  set()
83
79
 
80
+ cancelEdit: ->
81
+ if @state.editing?.model.isNew()
82
+ @props.query.results.removeRow(@state.editing.index)
83
+ @setState(editing: null)
84
+
85
+ saveEdit: ->
86
+ @setState(editing: null)
87
+
88
+ onRowClick: (model, selectedIndex, position) ->
89
+ @startEdit(selectedIndex, {position, model})
90
+
84
91
  render: ->
85
92
  cellStyles = new Lanes.Components.Grid.CellStyles(@query.fields)
93
+
86
94
  <div className='grid-component'>
87
95
  <Lanes.Components.Grid.Toolbar {...@props} startEdit={@startEdit} />
88
96
  <Lanes.Components.Grid.Header {...@props} cellStyles={cellStyles} />
89
97
  <Lanes.Components.Grid.Body
90
98
  {...@props}
99
+ ref='body'
91
100
  editing={@state.editing}
101
+ onEditSave={@saveEdit}
92
102
  onEditCancel={@cancelEdit}
93
103
  isLoading={@state.isLoading}
94
104
  cellStyles={cellStyles}
@@ -12,7 +12,8 @@ class CheckBox extends Lanes.React.BaseComponent
12
12
  <input type="checkbox" checked={selected} onChange={@onChange} />
13
13
 
14
14
 
15
- class Lanes.Components.Grid.Selections
15
+
16
+ DEFAULTS =
16
17
  id: 'selected'
17
18
  query: false
18
19
  textAlign: 'center'
@@ -21,7 +22,9 @@ class Lanes.Components.Grid.Selections
21
22
  sortBy: (row, indx, all) ->
22
23
  false == this.xtraData(indx)?.selected
23
24
 
25
+ class Lanes.Components.Grid.Selections
24
26
  constructor: (options) ->
27
+ _.extend(@, DEFAULTS)
25
28
  @onChange = options.onChange
26
29
  @choices = {}
27
30
  _.bindAll(@, 'onColumnClick')
@@ -9,7 +9,7 @@ class Lanes.Components.Grid.Toolbar extends Lanes.React.BaseComponent
9
9
  ])
10
10
 
11
11
  onAddRecord: ->
12
- model = @props.query.results.addBlankRow(0)
12
+ @props.query.results.addBlankRow(0)
13
13
  @props.startEdit(0)
14
14
 
15
15
  AddButton: ->
@@ -44,11 +44,11 @@ class Lanes.Components.RecordFinder extends Lanes.React.Component
44
44
  null
45
45
 
46
46
  getValue: ->
47
- if @props.parentModel
47
+ value = if @props.parentModel
48
48
  @props.parentModel[@props.associationName][@props.name]
49
49
  else
50
50
  @props.model[@props.name]
51
-
51
+ value or ''
52
52
 
53
53
  render: ->
54
54
  findIcon = <button className="btn btn-primary icon icon-search icon-lg" onClick={@showFinder}/>
@@ -3,25 +3,20 @@ class Lanes.Components.SelectField extends Lanes.React.Component
3
3
 
4
4
  propTypes:
5
5
  choices: React.PropTypes.arrayOf(
6
- React.PropTypes.shape({
7
- id: React.PropTypes.any
8
- label: React.PropTypes.string
9
- })
6
+ React.PropTypes.object
10
7
  )
11
- model: Lanes.PropTypes.Model
8
+ model: Lanes.PropTypes.State.isRequired
9
+ idField: React.PropTypes.string
12
10
  labelField: React.PropTypes.string
13
11
  getSelection: React.PropTypes.func
14
12
  setSelection: React.PropTypes.func
15
13
  displayLimit: React.PropTypes.number
16
14
  syncOptions: React.PropTypes.object
17
15
  multiSelect: React.PropTypes.bool
18
- fetchWhenOpen: React.PropTypes.bool
19
- allowFreeForm: React.PropTypes.bool
20
16
  includeBlankRow: React.PropTypes.bool
21
- displayFallback: React.PropTypes.string
22
17
 
23
18
  getDefaultProps: ->
24
- labelField: 'code', idField: 'id'
19
+ labelField: 'label', idField: 'id'
25
20
 
26
21
  dataObjects:
27
22
  query: ->
@@ -31,24 +26,29 @@ class Lanes.Components.SelectField extends Lanes.React.Component
31
26
  syncOptions: Lanes.Models.Query.mergedSyncOptions(@props.syncOptions)
32
27
  src: src
33
28
  fields: [
34
- {id: (@props.model?.idAttribute or 'id'), visible: false},
29
+ {id: @props.idField, visible: false},
35
30
  @props.labelField
36
31
  ]
37
32
  })
38
33
 
39
34
  renderDisplayValue: ->
40
- value = @getValue()?[@props.labelField]
41
- <span>{value}</span>
35
+ value = @getValue()
36
+ label = if _.isArray(value)
37
+ _.toSentence( _.map(value, @props.labelField) )
38
+ else if _.isObject(value)
39
+ value[@props.labelField]
40
+ else
41
+ value
42
+ <span>{label}</span>
42
43
 
43
44
  getValue: ->
44
45
  return undefined if @state.isOpen and not @props.multiSelect
45
46
  return @state.tempDisplayValue if @state.tempDisplayValue
46
47
  model = @props.getSelection?(@model, @props) or @model?[@props.name]
47
- return undefined unless model
48
- return model if @props.multiSelect
48
+ return model if @props.multiSelect or not model?
49
49
  label = model[@props.labelField] or @props.defaultLabel
50
50
  if !label and not _.isEmpty(@props.choices)
51
- label = _.findWhere( @props.choices, id: model.id)?[@props.labelField]
51
+ label = _.find( @props.choices, id: model.id)?[@props.labelField]
52
52
  if label
53
53
  {id: model.id, "#{@props.labelField}": label}
54
54
  else if model.id
@@ -81,7 +81,10 @@ class Lanes.Components.SelectField extends Lanes.React.Component
81
81
  else
82
82
  if _.isObject(value)
83
83
  model = if Lanes.u.isState(value) then value else new @query.model(value)
84
- model.fetch(@props.syncOptions).then(@setModel)
84
+ if false is @props.fetchOnSelect
85
+ @setModel(model)
86
+ else
87
+ model.fetch(@props.syncOptions).then(@setModel)
85
88
  @setState(isOpen: false, tempDisplayValue: value, requestInProgress: true)
86
89
  else
87
90
  if not @props.choices
@@ -1,4 +1,4 @@
1
- @import "lanes/vendor/widgets";
1
+ @import "lanes/vendor/styles/widgets";
2
2
 
3
3
  .rw-combobox, .rw-datetimepicker, .rw-numberpicker, .rw-dropdownlist {
4
4
  padding-bottom: 1px; // push down so border isn't covered
@@ -27,9 +27,9 @@ Lanes.Components.Form.FieldMixin = {
27
27
 
28
28
  _getValue: ->
29
29
  if @props.getValue
30
- @props.getValue.call(@model, @props)
30
+ @props.getValue.call(@model, @props) or ''
31
31
  else
32
- @model[@props.name]
32
+ @model[@props.name] or ''
33
33
 
34
34
  _setValue: (value) ->
35
35
  if @props.setValue then @props.setValue(value) else @model[@props.name] = value
@@ -4,16 +4,5 @@ class Lanes.Components.Input extends Lanes.React.Component
4
4
  Lanes.Components.Form.InputFieldMixin
5
5
  ]
6
6
 
7
- renderInputField: (props, handlers, label) ->
8
- if @props.inputOnly then @renderPlain(props, handlers) else @renderStyled(props, handlers, label)
9
-
10
- renderPlain: (props, handlers) ->
11
- <input {...props} {...handlers} />
12
-
13
- renderStyled: (props, handlers, label) ->
14
- colProps = _.omit(@props, 'name', 'label', 'type', 'editing', 'display')
15
-
16
- colClassName = _.classnames("align-#{@props.align}": @props.align, @formGroupClassNames(), 'field')
17
- <BS.Col {...colProps} className={colClassName}>
18
- <BS.Input {...props} {...handlers} />
19
- </BS.Col>
7
+ renderInputField: (props, handlers) ->
8
+ <BS.Input standalone {...props} {...handlers} />
@@ -13,7 +13,7 @@ Lanes.Components.Form.InputFieldMixin =
13
13
  type: 'text'
14
14
 
15
15
  getValue: ->
16
- @refs.input.getValue()
16
+ @refs.input.getValue() or ''
17
17
 
18
18
  handleKeyDown: (ev) ->
19
19
  @props.onEnter() if ev.key is 'Enter'
@@ -26,23 +26,30 @@ Lanes.Components.Form.InputFieldMixin =
26
26
  @props.onBlur?()
27
27
 
28
28
  renderEdit: (label) ->
29
- value = @props.value or @_getValue()
30
- label ||= @props.label or _.field2title(@props.name)
29
+ value = @props.value or @_getValue() or ''
31
30
 
32
31
  props = _.extend({
33
32
  ref: 'input'
34
- className: _.classnames('value',
33
+ className: _.classnames('edit',
35
34
  changeset: @state.changeset
36
35
  )
37
-
38
36
  label: if @props.unlabeled then false else label
39
- onChange: @handleChange
40
37
  }, @props, {value: value})
41
38
 
42
- handlers = { onBlur: @onFieldBlur }
39
+ handlers = { onBlur: @onFieldBlur, onChange: @handleChange }
43
40
 
44
41
  if @isFieldValueInvalid() then props.bsStyle = 'error'
45
42
  if @props.onEnter then handlers.onKeyDown = @handleKeyDown
46
43
  if @props.selectOnFocus then handlers.onFocus = @selectOnFocus
47
44
 
48
- @renderInputField(props, handlers, label)
45
+ props = _.omit(props, 'label')
46
+ field = @renderInputField(props, handlers)
47
+
48
+ if props.inputOnly
49
+ field
50
+ else
51
+ label ||= @props.label or _.field2title(@props.name)
52
+
53
+ <LC.FormGroup display {...props} label={label}>
54
+ {field}
55
+ </LC.FormGroup>
@@ -1,7 +1,7 @@
1
1
  class Lanes.Components.NetworkActivityOverlay extends Lanes.React.Component
2
2
 
3
3
  propTypes:
4
- model: Lanes.PropTypes.Model.isRequired
4
+ model: Lanes.PropTypes.Model
5
5
  message: React.PropTypes.string
6
6
  timeout: React.PropTypes.number
7
7
  visible: React.PropTypes.bool
@@ -4,12 +4,14 @@ class Lanes.Components.NumberInput extends Lanes.React.Component
4
4
  Lanes.Components.Form.InputFieldMixin
5
5
  ]
6
6
  handleNumberChange: (n) ->
7
- @handleChange(target: value: n)
7
+ value = if _.isNull(n) then 0 else n
8
+ @handleChange(target: {value})
8
9
 
9
10
  renderInputField: (props, handlers, label) ->
10
11
  props.format ||= '#,###.00'
11
12
  props = _.omit(props, 'label')
12
- input = <Lanes.Vendor.ReactWidgets.NumberPicker
13
+
14
+ <Lanes.Vendor.ReactWidgets.NumberPicker
13
15
  ref="select"
14
16
  className={@props.className}
15
17
  {...handlers}
@@ -17,13 +19,3 @@ class Lanes.Components.NumberInput extends Lanes.React.Component
17
19
  onChange={@handleNumberChange}
18
20
  value={Number(props.value)}
19
21
  />
20
- if @props.unstyled
21
- input
22
- else
23
- <LC.FormGroup
24
- {...@props}
25
- className={@formGroupClassNames()}
26
- label={@getLabelValue()}
27
- >
28
- {input}
29
- </LC.FormGroup>
@@ -5,7 +5,6 @@ class Lanes.Components.ToggleField extends Lanes.React.Component
5
5
 
6
6
  renderDisplayValue: ->
7
7
  <Lanes.Vendor.ReactToggle
8
- defaultChecked={!!@props.model[@props.name]}
9
8
  checked={!!@props.model[@props.name]}
10
9
  disabled={true}
11
10
  />
@@ -19,7 +18,6 @@ class Lanes.Components.ToggleField extends Lanes.React.Component
19
18
  toggle = <Lanes.Vendor.ReactToggle
20
19
  onChange={@handleToggleChange}
21
20
  checked={!!@props.model[@props.name]}
22
- defaultChecked={!!@props.model[@props.name]}
23
21
  />
24
22
  if @props.unstyled
25
23
  toggle
@@ -26,6 +26,15 @@ label.field {
26
26
  }
27
27
 
28
28
  }
29
+ &.edit {
30
+ // bootstrap styles
31
+ .value > div > input:only-child {
32
+ border-top-left-radius: $border-radius-base;
33
+ border-top-right-radius: $border-radius-base;
34
+ border-bottom-left-radius: $border-radius-base;
35
+ border-bottom-right-radius: $border-radius-base;
36
+ }
37
+ }
29
38
  &.read-only .input-group {
30
39
  @extend .form-control !optional;
31
40
  padding: 6px 12px;
@@ -4,7 +4,8 @@
4
4
  @import "./overlay";
5
5
  @import "./image-saver";
6
6
  @import "./throbber";
7
- @import "lanes/vendor/toggle";
7
+ @import "lanes/vendor/styles/toggle";
8
+ @import "lanes/vendor/styles/widgets";
8
9
 
9
10
  .record-finder {
10
11
  .icon { cursor: pointer; }
@@ -26,7 +26,7 @@ class Lanes.Components.Toolbar extends Lanes.React.Component
26
26
  <Lanes.Vendor.ReactToggle
27
27
  aria-labelledby="Editing"
28
28
  onChange={@props.commands.toggleEdit}
29
- defaultChecked={@props.commands.isEditing()} />
29
+ checked={@props.commands.isEditing()} />
30
30
  <span>Edit</span>
31
31
  </label>
32
32
  </li>
@@ -3,7 +3,7 @@ REACT_CACHE = Object.create(null)
3
3
  Lanes.lib.HotReload =
4
4
 
5
5
  remember: (klass) ->
6
- return klass unless klass::FILE
6
+ return klass # unless klass::FILE
7
7
  path = klass::FILE.path.join("/") + ".js"
8
8
  if REACT_CACHE[path]
9
9
  return klass
@@ -24,7 +24,7 @@ Lanes.lib.HotReload =
24
24
  Lanes.Vendor.deepForceUpdate(viewport.reactRoot)
25
25
 
26
26
  initiate: (assets) ->
27
- Lanes.lib.RequestAssets (_.pluck(assets, 'path'))...
27
+ Lanes.lib.RequestAssets (_.map(assets, 'path'))...
28
28
  .then (a) =>
29
29
  for asset in assets
30
30
  if asset.type == "css"
@@ -1,5 +1,5 @@
1
1
  ##= require ./HotReload
2
- ##= require lanes/vendor/development
2
+ ##= require lanes/vendor/development/helpers
3
3
  ##= require_self
4
4
 
5
5
  Lanes.log.setDefaultLevel(Lanes.log.levels.TRACE)
@@ -15,13 +15,13 @@ class Loader
15
15
  this.head = document.querySelector('head')
16
16
  this.body = document.body
17
17
 
18
- _.each(urls, (url) ->
19
- url += "?#{parseInt(Math.random() * 100000)}"
18
+ for baseUrl in urls
19
+ url = "#{baseUrl}?#{parseInt(Math.random() * 100000)}"
20
20
  if /.css($|\?)/.test(url)
21
21
  this.loadCSS(url, onComplete)
22
22
  else
23
23
  this.loadJS(url, onComplete)
24
- , this)
24
+
25
25
 
26
26
 
27
27
  loadCSS: (url, fn) ->
@@ -161,7 +161,7 @@ class Lanes.Models.AssocationMap
161
161
  return ret if options.saveDepth > 5
162
162
  for name, def_options of @definitions when @isCreated(model, name)
163
163
  continue if def_options.readOnly or
164
- (options.onlyAssociations and not _.include(options.onlyAssociations, name))
164
+ (options.onlyAssociations and not _.includes(options.onlyAssociations, name))
165
165
  assoc = model[name]
166
166
  ret[name] = assoc.dataForSave(
167
167
  _.extend({}, options, def_options)
@@ -50,6 +50,7 @@ ProxyMethods = {
50
50
  api_path: -> @_proxied_model::api_path()
51
51
  getId: -> @_proxied_options.parent[@_proxied_config.association_pk]
52
52
  isNew: -> _.isBlank(@getId())
53
+ clear: -> null
53
54
  invalidMessageFor: (name) ->
54
55
  if @_proxied_model::_definition[name]?.required
55
56
  "Cannot be empty"
@@ -1,7 +1,7 @@
1
1
  # These prototype properties are also
2
2
  # set on any Collections that are created
3
3
  PROPERTIES_SHARED_WITH_DEFAULT_COLLECTION = [
4
- 'cacheDuration'
4
+
5
5
  ]
6
6
 
7
7
  # Da Model. Handles all things dataish
@@ -65,8 +65,8 @@ class BaseModel
65
65
  _.dasherize(_.last(@FILE?.path || ''))
66
66
 
67
67
  api_path: ->
68
- id = @FILE?.extension.identifier || ''
69
- id + '/' + _.pluralize(@modelTypeIdentifier())
68
+ id = @FILE?.extension.identifier
69
+ ( if id then "/#{id}" else '' ) + '/' + _.pluralize(@modelTypeIdentifier())
70
70
 
71
71
  urlRoot: ->
72
72
  Lanes.config.api_path + _.result(this, 'api_path')
@@ -163,10 +163,7 @@ class BaseModel
163
163
  # triggering a `"change"` event.
164
164
  fetch: (original_options = {}) ->
165
165
  options = _.extend({}, original_options, {limit:1, ignoreUnsaved:true})
166
- if this.cacheDuration && _.isEmpty(original_options)
167
- Lanes.Models.ServerCache.fetchRecord(this, options)
168
- else
169
- this.sync('read', this, options)
166
+ this.sync('read', this, options)
170
167
 
171
168
  @fetch: (options = {}) ->
172
169
  record = new this()
@@ -217,8 +214,8 @@ class BaseModel
217
214
  # Check if an attribute named "name" can be set to "value"
218
215
  # Returns an empty string if value, and an appropriate error message if not
219
216
  invalidMessageFor: (name) ->
220
- return '' unless @unmaskedInvalidFields and _.include(@requiredAttributes, name) and
221
- _.include(@unmaskedInvalidFields, name)
217
+ return '' unless @unmaskedInvalidFields and _.includes(@requiredAttributes, name) and
218
+ _.includes(@unmaskedInvalidFields, name)
222
219
 
223
220
  if @isBlank(name)
224
221
  "Cannot be empty"
@@ -234,7 +231,7 @@ class BaseModel
234
231
  @trigger("invalid-fields", this, @unmaskedInvalidFields)
235
232
  else if @unmaskedInvalidFields isnt 'all'
236
233
  @unmaskedInvalidFields ||= []
237
- if _.include(@requiredAttributes, attr) and !_.include(@unmaskedInvalidFields, attr)
234
+ if _.includes(@requiredAttributes, attr) and !_.includes(@unmaskedInvalidFields, attr)
238
235
  @unmaskedInvalidFields.push(attr)
239
236
  @trigger("invalid-field:#{attr}", this)
240
237