lanes 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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