lanes 0.3.0 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +2 -0
- data/client/lanes/Config.coffee +1 -1
- data/client/lanes/access/LoginDialog.cjsx +1 -1
- data/client/lanes/access/Roles.coffee +1 -1
- data/client/lanes/access/User.coffee +2 -2
- data/client/lanes/access/screens/user-management/UserManagement.cjsx +1 -1
- data/client/lanes/components/calendar/styles.scss +1 -1
- data/client/lanes/components/grid/Body.cjsx +5 -2
- data/client/lanes/components/grid/EditingMixin.cjsx +3 -0
- data/client/lanes/components/grid/Editor.cjsx +3 -11
- data/client/lanes/components/grid/Grid.cjsx +22 -12
- data/client/lanes/components/grid/Selections.cjsx +4 -1
- data/client/lanes/components/grid/Toolbar.cjsx +1 -1
- data/client/lanes/components/record-finder/RecordFinder.cjsx +2 -2
- data/client/lanes/components/select-field/SelectField.cjsx +19 -16
- data/client/lanes/components/select-field/styles.scss +1 -1
- data/client/lanes/components/shared/FieldMixin.cjsx +2 -2
- data/client/lanes/components/shared/Input.cjsx +2 -13
- data/client/lanes/components/shared/InputFieldMixin.cjsx +15 -8
- data/client/lanes/components/shared/NetworkActivityOverlay.cjsx +1 -1
- data/client/lanes/components/shared/NumberInput.cjsx +4 -12
- data/client/lanes/components/shared/ToggleField.cjsx +0 -2
- data/client/lanes/components/shared/fields.scss +9 -0
- data/client/lanes/components/shared/styles.scss +2 -1
- data/client/lanes/components/toolbar/Toolbar.cjsx +1 -1
- data/client/lanes/lib/HotReload.coffee +2 -2
- data/client/lanes/lib/development.coffee +1 -1
- data/client/lanes/lib/loader.coffee +3 -3
- data/client/lanes/models/AssociationMap.coffee +1 -1
- data/client/lanes/models/AssociationProxy.coffee +1 -0
- data/client/lanes/models/Base.coffee +7 -10
- data/client/lanes/models/Collection.coffee +3 -6
- data/client/lanes/models/JobStatus.coffee +1 -1
- data/client/lanes/models/PubSub.coffee +51 -33
- data/client/lanes/models/Query.coffee +1 -1
- data/client/lanes/models/Sync.coffee +1 -1
- data/client/lanes/models/User.coffee +3 -3
- data/client/lanes/models/mixins/FileSupport.coffee +3 -3
- data/client/lanes/models/query/ArrayResult.coffee +3 -6
- data/client/lanes/models/query/CollectionResult.coffee +5 -3
- data/client/lanes/react/Component.coffee +2 -2
- data/client/lanes/react/DefaultComponentNotFound.cjsx +2 -2
- data/client/lanes/react/Screen.coffee +1 -1
- data/client/lanes/react/Viewport.coffee +1 -1
- data/client/lanes/react/mixins/Access.coffee +1 -1
- data/client/lanes/react/mixins/Data.coffee +9 -5
- data/client/lanes/screens/Commands.coffee +1 -1
- data/client/lanes/screens/UserPreferences.cjsx +1 -1
- data/client/lanes/testing/BeforeEach.coffee +7 -0
- data/client/lanes/vendor/base.js.erb +5 -0
- data/client/lanes/vendor/calendar.js.erb +5 -0
- data/client/lanes/vendor/commons.js.erb +5 -0
- data/client/lanes/vendor/{base.js → development/base.js} +37776 -40850
- data/client/lanes/vendor/development/calendar.js +1667 -0
- data/client/lanes/vendor/development/commons.js +39085 -0
- data/client/lanes/vendor/development/helpers.js +578 -0
- data/client/lanes/vendor/{toggle.js → development/toggle.js} +22 -82
- data/client/lanes/vendor/development/widgets.js +8975 -0
- data/client/lanes/vendor/production/base.js +63239 -0
- data/client/lanes/vendor/production/calendar.js +1667 -0
- data/client/lanes/vendor/production/commons.js +38505 -0
- data/client/lanes/vendor/production/toggle.js +285 -0
- data/client/lanes/vendor/production/widgets.js +8975 -0
- data/client/lanes/vendor/{calendar.scss → styles/calendar.scss} +6 -0
- data/client/lanes/vendor/{toggle.scss → styles/toggle.scss} +0 -0
- data/client/lanes/vendor/{widgets.scss → styles/widgets.scss} +2 -2
- data/client/lanes/vendor/toggle.js.erb +5 -0
- data/client/lanes/vendor/widgets.js.erb +5 -0
- data/lib/lanes/api/default_routes.rb +3 -3
- data/lib/lanes/api/routing.rb +1 -1
- data/lib/lanes/configuration.rb +8 -14
- data/lib/lanes/environment.rb +3 -0
- data/lib/lanes/extension/definition.rb +4 -0
- data/lib/lanes/system_settings.rb +21 -6
- data/lib/lanes/version.rb +1 -1
- data/npm-build/base.js +9 -4
- data/npm-build/build +9 -0
- data/npm-build/development.js +3 -1
- data/npm-build/package.json +34 -34
- data/npm-build/update-dayz +1 -1
- data/npm-build/webpack.config.js +36 -20
- data/spec/command-reference-files/initial/Gemfile +1 -1
- data/spec/command-reference-files/screen/config/screens.rb +1 -1
- data/spec/lanes/components/grid/RowEditorSpec.coffee +3 -1
- data/spec/lanes/components/select-field/SelectFieldSpec.coffee +33 -28
- data/spec/lanes/models/AssociationProxySpec.coffee +36 -37
- data/spec/lanes/models/BaseSpec.coffee +0 -32
- data/spec/lanes/models/CollectionSpec.coffee +0 -10
- data/spec/lanes/models/PubSubSpec.coffee +63 -13
- data/spec/lanes/screens/DefinitionsSpec.coffee +2 -2
- metadata +23 -20
- data/client/lanes/vendor/calendar.js +0 -17301
- data/client/lanes/vendor/commons.js +0 -19722
- data/client/lanes/vendor/development.js +0 -5471
- data/client/lanes/vendor/grid.js +0 -15384
- data/client/lanes/vendor/grid.scss +0 -928
- data/client/lanes/vendor/rw-widgets.eot +0 -0
- data/client/lanes/vendor/rw-widgets.svg +0 -18
- data/client/lanes/vendor/rw-widgets.ttf +0 -0
- data/client/lanes/vendor/rw-widgets.woff +0 -0
- data/client/lanes/vendor/widgets.js +0 -23204
- data/npm-build/compile.coffee +0 -19
- data/spec/lanes/models/ServerCacheSpec.coffee +0 -65
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4672ec1ecf5544a9da08b8eb826b5e573987ac7d
|
4
|
+
data.tar.gz: 53fb32ae3e09dec506b5cb9e1a961444c61bb122
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a8a6599cce4d9aaa1e0bcea8969636d7d83ecbd6263e4d6a325743af0531287ce74dee0b6fb69577b6607906114fbe4483bf1516be174f3a767279fa53ac65e8
|
7
|
+
data.tar.gz: f5e2136c4240d70c59c7ab485879e075d3600b0f4336e1b7da185823b4bdbcabaddae9abc38361f53b803c8fb4074583500b718df1f1e01db0eecaa6df1b975e
|
data/.gitignore
CHANGED
data/client/lanes/Config.coffee
CHANGED
@@ -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()
|
@@ -66,7 +66,7 @@ class Lanes.Models.UserRoleSet
|
|
66
66
|
return this.testModelAccess(method, model)
|
67
67
|
|
68
68
|
testModelAccess:(method, model) ->
|
69
|
-
!!_.
|
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 = _.
|
14
|
+
options.model.role_names = _.map(roles, 'id')
|
15
15
|
|
16
16
|
editors: (props) ->
|
17
17
|
role_names: ({model}) =>
|
@@ -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
|
-
|
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(@
|
14
|
+
@props.query.results.removeRow(@props.editing.index)
|
15
15
|
else
|
16
|
-
@props.query.results.saveModelChanges(model, @
|
17
|
-
|
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: (
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
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(
|
69
|
+
@setState( _.extend({}, attrs, {editing}) )
|
74
70
|
if @props.onSelectionChange
|
75
|
-
osc = @props.onSelectionChange(
|
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
|
-
|
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')
|
@@ -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.
|
7
|
-
id: React.PropTypes.any
|
8
|
-
label: React.PropTypes.string
|
9
|
-
})
|
6
|
+
React.PropTypes.object
|
10
7
|
)
|
11
|
-
model: Lanes.PropTypes.
|
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: '
|
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:
|
29
|
+
{id: @props.idField, visible: false},
|
35
30
|
@props.labelField
|
36
31
|
]
|
37
32
|
})
|
38
33
|
|
39
34
|
renderDisplayValue: ->
|
40
|
-
value = @getValue()
|
41
|
-
|
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
|
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 = _.
|
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
|
-
|
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
|
@@ -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
|
8
|
-
|
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('
|
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
|
-
|
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>
|
@@ -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
|
-
|
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
|
-
|
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;
|
@@ -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
|
-
|
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 (_.
|
27
|
+
Lanes.lib.RequestAssets (_.map(assets, 'path'))...
|
28
28
|
.then (a) =>
|
29
29
|
for asset in assets
|
30
30
|
if asset.type == "css"
|
@@ -15,13 +15,13 @@ class Loader
|
|
15
15
|
this.head = document.querySelector('head')
|
16
16
|
this.body = document.body
|
17
17
|
|
18
|
-
|
19
|
-
url
|
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
|
-
|
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 _.
|
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
|
-
|
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
|
-
|
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 _.
|
221
|
-
_.
|
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 _.
|
234
|
+
if _.includes(@requiredAttributes, attr) and !_.includes(@unmaskedInvalidFields, attr)
|
238
235
|
@unmaskedInvalidFields.push(attr)
|
239
236
|
@trigger("invalid-field:#{attr}", this)
|
240
237
|
|