lanes 0.5.0 → 0.5.5
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.
- checksums.yaml +4 -4
- data/client/fonts/fontawesome-webfont.woff +0 -0
- data/client/fonts/fontawesome-webfont.woff2 +0 -0
- data/client/lanes/Boot.cjsx +1 -6
- data/client/lanes/components/grid/Body.cjsx +14 -1
- data/client/lanes/components/grid/Grid.cjsx +20 -19
- data/client/lanes/components/grid/Toolbar.cjsx +7 -4
- data/client/lanes/components/grid/editors.scss +1 -1
- data/client/lanes/components/grid/styles.scss +16 -5
- data/client/lanes/components/modal/Modal.cjsx +9 -11
- data/client/lanes/components/record-finder/RecordFinder.cjsx +2 -2
- data/client/lanes/components/record-finder/styles.scss +7 -5
- data/client/lanes/components/shared/FormGroup.cjsx +1 -1
- data/client/lanes/components/shared/Icon.cjsx +3 -2
- data/client/lanes/components/shared/Input.cjsx +1 -0
- data/client/lanes/components/shared/PanelHeader.cjsx +8 -0
- data/client/lanes/components/shared/fields.scss +5 -4
- data/client/lanes/components/shared/styles.scss +18 -0
- data/client/lanes/index.js +0 -1
- data/client/lanes/{plugins → lib}/ResizeSensor.js +0 -0
- data/client/lanes/lib/all.js +13 -0
- data/client/lanes/lib/dom.coffee +1 -1
- data/client/lanes/lib/format.coffee +2 -2
- data/client/lanes/lib/index.js.erb +1 -13
- data/client/lanes/lib/loader.coffee +2 -2
- data/client/lanes/lib/utilFunctions.coffee +12 -0
- data/client/lanes/models/AssociationMap.coffee +27 -18
- data/client/lanes/models/Base.coffee +12 -4
- data/client/lanes/models/Collection.coffee +5 -3
- data/client/lanes/models/PubSub.coffee +1 -1
- data/client/lanes/models/Query.coffee +0 -1
- data/client/lanes/models/State.coffee +5 -1
- data/client/lanes/models/Sync.coffee +5 -9
- data/client/lanes/models/query/ArrayResult.coffee +27 -7
- data/client/lanes/models/query/Result.coffee +2 -0
- data/client/lanes/react/Component.coffee +3 -3
- data/client/lanes/react/Viewport.coffee +17 -5
- data/client/lanes/react/mixins/Access.coffee +2 -2
- data/client/lanes/react/mixins/FieldErrors.coffee +3 -3
- data/client/lanes/remote/BaseClasses.coffee +0 -0
- data/client/lanes/remote/api.coffee +8 -0
- data/client/lanes/styles/fonts/_icons.scss +139 -2
- data/client/lanes/styles/fonts/_variables.scss +142 -4
- data/client/lanes/styles/global/mixins.scss +5 -0
- data/client/lanes/styles/global/styles.scss +5 -2
- data/client/lanes/styles/global.scss +1 -0
- data/client/lanes/vendor/base.js.erb +4 -2
- data/client/lanes/vendor/development/calendar.js +65 -65
- data/client/lanes/vendor/development/commons.js +34530 -34719
- data/client/lanes/vendor/development/data.js +30832 -0
- data/client/lanes/vendor/development/helpers.js +26 -26
- data/client/lanes/vendor/development/toggle.js +19 -19
- data/client/lanes/vendor/development/ui.js +22568 -0
- data/client/lanes/vendor/development/widgets.js +362 -362
- data/client/lanes/vendor/production/calendar.js +65 -65
- data/client/lanes/vendor/production/commons.js +34360 -34549
- data/client/lanes/vendor/production/data.js +30829 -0
- data/client/lanes/vendor/production/toggle.js +19 -19
- data/client/lanes/vendor/production/ui.js +22564 -0
- data/client/lanes/vendor/production/widgets.js +362 -362
- data/client/lanes/vendor/{production/base.js → standalone/index.js} +43836 -53602
- data/client/lanes/workspace/Modal.cjsx +1 -1
- data/client/lanes/workspace/styles/header.scss +1 -0
- data/client/lanes/workspace/styles/layout.scss +12 -0
- data/lanes.gemspec +1 -0
- data/lib/lanes/access/authentication_provider.rb +4 -3
- data/lib/lanes/api/coffeescript_processor.rb +9 -3
- data/lib/lanes/api/{controller.rb → controller_base.rb} +3 -35
- data/lib/lanes/api/formatted_reply.rb +2 -2
- data/lib/lanes/api/generic_controller.rb +42 -0
- data/lib/lanes/api/helper_methods.rb +1 -1
- data/lib/lanes/api/null_authentication_provider.rb +3 -0
- data/lib/lanes/api/request_wrapper.rb +32 -18
- data/lib/lanes/api/root.rb +25 -3
- data/lib/lanes/api/routing.rb +41 -22
- data/lib/lanes/api/sprockets_extension.rb +3 -1
- data/lib/lanes/api.rb +2 -1
- data/lib/lanes/configuration.rb +0 -1
- data/lib/lanes/extension/definition.rb +5 -1
- data/lib/lanes/hot_reload_plugin.rb +0 -1
- data/lib/lanes/version.rb +1 -1
- data/npm-build/build +3 -0
- data/npm-build/{base.js → data.js} +16 -16
- data/npm-build/package.json +3 -1
- data/npm-build/standalone.js +4 -0
- data/npm-build/ui.js +8 -0
- data/npm-build/webpack-standalone.config.js +16 -0
- data/npm-build/webpack.config.js +4 -3
- data/templates/config/lanes.rb +3 -3
- metadata +34 -10
- data/client/lanes/lib/noConflict.coffee +0 -15
- data/client/lanes/plugins/index.js +0 -1
- data/client/lanes/vendor/development/base.js +0 -61239
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 423cf2958270fce5f4d1fb05fbba10fd56afbcd8
|
4
|
+
data.tar.gz: e5a90b6559ebbadf4c9eb63833d0aa59e1b4d017
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7f24e95dc672cdb9d18f6937fac870a5d216046739771d534291997369ab4488c807c92a7ad82151428b310466970085e69fd6f7c48caffd94f0a5471baa97cc
|
7
|
+
data.tar.gz: f680982d7d8767bfc225b61bfd38a97e6ab11185d426e60a6c3fad7319479d7433f21bc2a2b843d24d00a32445a9e84c49f611e5cf515f06531216237cd497c6
|
Binary file
|
Binary file
|
data/client/lanes/Boot.cjsx
CHANGED
@@ -1,9 +1,4 @@
|
|
1
1
|
Lanes.renderScreenTo = (selector, options) ->
|
2
2
|
Lanes.config.bootstrap(options)
|
3
3
|
document.addEventListener "DOMContentLoaded", ->
|
4
|
-
viewport = new Lanes.React.Viewport(selector
|
5
|
-
Lanes.Models.PubSub.initialize()
|
6
|
-
Lanes.Extensions.fireOnInitialized(viewport)
|
7
|
-
viewport.renderRoot()
|
8
|
-
Lanes.Extensions.fireOnAvailable(viewport)
|
9
|
-
viewport.onBoot()
|
4
|
+
viewport = new Lanes.React.Viewport({selector, options})
|
@@ -1,3 +1,12 @@
|
|
1
|
+
class AllRows extends Lanes.React.BaseComponent
|
2
|
+
render: ->
|
3
|
+
len = @props.length
|
4
|
+
rows = []
|
5
|
+
for i in [0...len - 1] by 1
|
6
|
+
rows.push @props.itemRenderer(i, i)
|
7
|
+
<div>{rows}</div>
|
8
|
+
|
9
|
+
|
1
10
|
class Lanes.Components.Grid.Body extends Lanes.React.BaseComponent
|
2
11
|
|
3
12
|
propTypes:
|
@@ -72,7 +81,10 @@ class Lanes.Components.Grid.Body extends Lanes.React.BaseComponent
|
|
72
81
|
{fields}
|
73
82
|
</div>
|
74
83
|
|
84
|
+
|
75
85
|
render: ->
|
86
|
+
Rows = if @props.renderCompleteResults then AllRows else Lanes.Vendor.List
|
87
|
+
|
76
88
|
<div className={_.classnames('grid-body', 'is-editing': @props.editing)}>
|
77
89
|
|
78
90
|
<LC.NetworkActivityOverlay model={@props.query} />
|
@@ -84,7 +96,8 @@ class Lanes.Components.Grid.Body extends Lanes.React.BaseComponent
|
|
84
96
|
onCancel={@props.onEditCancel}
|
85
97
|
editing={@props.editing} />
|
86
98
|
|
87
|
-
|
99
|
+
|
100
|
+
<Rows
|
88
101
|
useTranslate3d
|
89
102
|
isEditing={!!@props.editing}
|
90
103
|
itemRenderer={@renderRow}
|
@@ -10,23 +10,6 @@
|
|
10
10
|
|
11
11
|
class Lanes.Components.Grid extends Lanes.React.Component
|
12
12
|
|
13
|
-
mixins: [
|
14
|
-
Lanes.React.Mixins.MonitorSize
|
15
|
-
]
|
16
|
-
|
17
|
-
dataObjects:
|
18
|
-
query: 'props'
|
19
|
-
|
20
|
-
bindDataEvents:
|
21
|
-
query: 'load change sort'
|
22
|
-
|
23
|
-
getInitialState: ->
|
24
|
-
{}
|
25
|
-
|
26
|
-
componentWillReceiveProps: (nextProps) ->
|
27
|
-
if nextProps.autoLoadQuery and nextProps.query isnt @props.query
|
28
|
-
nextProps.query.ensureLoaded()
|
29
|
-
|
30
13
|
propTypes:
|
31
14
|
query: React.PropTypes.instanceOf(Lanes.Models.Query).isRequired
|
32
15
|
width: React.PropTypes.number
|
@@ -40,17 +23,35 @@ class Lanes.Components.Grid extends Lanes.React.Component
|
|
40
23
|
onColumnClick: React.PropTypes.func
|
41
24
|
onSelectionChange: React.PropTypes.func
|
42
25
|
autoLoadQuery: React.PropTypes.bool
|
26
|
+
renderCompleteResults: React.PropTypes.bool
|
43
27
|
toolbarChildren: React.PropTypes.oneOfType([
|
44
28
|
React.PropTypes.element,
|
45
29
|
React.PropTypes.arrayOf(React.PropTypes.element)
|
46
30
|
])
|
47
31
|
|
48
|
-
|
49
|
-
|
32
|
+
mixins: [
|
33
|
+
Lanes.React.Mixins.MonitorSize
|
34
|
+
]
|
35
|
+
|
36
|
+
dataObjects:
|
37
|
+
query: 'props'
|
38
|
+
|
39
|
+
bindDataEvents:
|
40
|
+
query: 'load change sort'
|
41
|
+
|
42
|
+
componentWillReceiveProps: (nextProps) ->
|
43
|
+
if nextProps.autoLoadQuery and nextProps.query isnt @props.query
|
44
|
+
nextProps.query.ensureLoaded()
|
50
45
|
|
51
46
|
componentWillMount: ->
|
52
47
|
@query.ensureLoaded() if @props.autoLoadQuery
|
53
48
|
|
49
|
+
getInitialState: ->
|
50
|
+
{}
|
51
|
+
|
52
|
+
getDefaultProps: ->
|
53
|
+
editorProps: {}, autoLoadQuery: true
|
54
|
+
|
54
55
|
onSortChange: (sortInfo) ->
|
55
56
|
for sortConfig in sortInfo
|
56
57
|
sort = @query.fields.at(sortConfig.name).sortBy
|
@@ -1,7 +1,7 @@
|
|
1
1
|
class Lanes.Components.Grid.Toolbar extends Lanes.React.BaseComponent
|
2
2
|
|
3
3
|
propTypes:
|
4
|
-
|
4
|
+
onAddRecord: React.PropTypes.func
|
5
5
|
startEdit: React.PropTypes.func
|
6
6
|
toolbarChildren: React.PropTypes.oneOfType([
|
7
7
|
React.PropTypes.element,
|
@@ -13,16 +13,19 @@ class Lanes.Components.Grid.Toolbar extends Lanes.React.BaseComponent
|
|
13
13
|
@props.startEdit(0)
|
14
14
|
|
15
15
|
AddButton: ->
|
16
|
-
return null unless @props.allowCreate
|
16
|
+
return null unless @props.onAddRecord and @props.allowCreate
|
17
17
|
<BS.Button className="navbar-btn add-row pull-right"
|
18
18
|
onClick={@onAddRecord} bsSize='small'
|
19
19
|
>
|
20
20
|
<LC.Icon type="plus" />Add Row
|
21
21
|
</BS.Button>
|
22
22
|
|
23
|
+
|
24
|
+
shouldDisplay: ->
|
25
|
+
not ( ( false == @props.commands?.isEditing() or not @props.allowCreate ) and not @props.toolbarChildren )
|
26
|
+
|
23
27
|
render: ->
|
24
|
-
|
25
|
-
return null
|
28
|
+
return null unless @shouldDisplay()
|
26
29
|
|
27
30
|
props = _.extend {}, @props,
|
28
31
|
<Lanes.Components.Grid.Toolbar key="toolbar" {...props} />
|
@@ -9,7 +9,6 @@
|
|
9
9
|
flex-direction: column;
|
10
10
|
flex: 1;
|
11
11
|
|
12
|
-
|
13
12
|
// styles shared between header and row
|
14
13
|
.header, .r {
|
15
14
|
display: flex;
|
@@ -17,13 +16,12 @@
|
|
17
16
|
min-height: 40px;
|
18
17
|
display: flex;
|
19
18
|
flex-direction: row;
|
19
|
+
page-break-inside: avoid;
|
20
20
|
.c {
|
21
21
|
padding: $table-cell-padding;
|
22
22
|
line-height: $line-height-base;
|
23
|
-
|
24
23
|
display: flex;
|
25
24
|
flex-direction: row;
|
26
|
-
|
27
25
|
&.center { justify-content: center; }
|
28
26
|
&.right { justify-content: flex-end; }
|
29
27
|
|
@@ -54,6 +52,11 @@
|
|
54
52
|
right: -5px;
|
55
53
|
color: lightgray;
|
56
54
|
}
|
55
|
+
&:not(.asc):not(.desc) {
|
56
|
+
&:after {
|
57
|
+
@include hidden-print;
|
58
|
+
}
|
59
|
+
}
|
57
60
|
&.asc:after {
|
58
61
|
color: gray;
|
59
62
|
content: $fa-var-sort-asc;
|
@@ -65,13 +68,21 @@
|
|
65
68
|
}
|
66
69
|
}
|
67
70
|
}
|
68
|
-
|
71
|
+
.r {
|
72
|
+
margin-right: 10px;
|
73
|
+
/* page-break-inside: avoid; */
|
74
|
+
break-inside: avoid-page;
|
75
|
+
}
|
69
76
|
.grid-body {
|
70
77
|
border-top: 1px solid $table-border-color;
|
71
78
|
overflow: auto;
|
72
79
|
position: relative; // for absolutely positioned row editor
|
73
80
|
flex-grow: 1;
|
74
|
-
height: 1px;
|
81
|
+
height: 1px; // panel needs height to force scroll
|
82
|
+
@media print {
|
83
|
+
overflow: visible;
|
84
|
+
height: initial;
|
85
|
+
}
|
75
86
|
.r:nth-child(odd) {
|
76
87
|
background-color: $table-bg-accent;
|
77
88
|
}
|
@@ -25,15 +25,15 @@ class Lanes.Components.Modal extends Lanes.React.Component
|
|
25
25
|
getInitialState: ->
|
26
26
|
show: false
|
27
27
|
|
28
|
-
onOkButton: -> @state.onOk?(this)
|
29
|
-
onCancelButton: -> @state.onCancel?(this)
|
30
|
-
onButton: (btn) ->
|
28
|
+
onOkButton: (ev) -> @state.onOk?(this, ev)
|
29
|
+
onCancelButton: (ev) -> @state.onCancel?(this, ev)
|
30
|
+
onButton: (ev, btn) ->
|
31
31
|
@selected = btn
|
32
|
-
@_hide() if @state.autoHide
|
33
32
|
if btn.eventKey is 'ok'
|
34
|
-
@onOkButton()
|
33
|
+
@onOkButton(ev)
|
35
34
|
else
|
36
|
-
@onCancelButton()
|
35
|
+
@onCancelButton(ev)
|
36
|
+
@_hide() if @state.autoHide and ev.defaultPrevented isnt true
|
37
37
|
|
38
38
|
componentWillReceiveProps: (nextProps) ->
|
39
39
|
@replaceState(nextProps)
|
@@ -46,9 +46,7 @@ class Lanes.Components.Modal extends Lanes.React.Component
|
|
46
46
|
@context.viewport.modalProps.show = true
|
47
47
|
@setState(show: true)
|
48
48
|
|
49
|
-
hide: ->
|
50
|
-
@_hide()
|
51
|
-
@state.onCancel?()
|
49
|
+
hide: -> @_hide()
|
52
50
|
|
53
51
|
render: ->
|
54
52
|
return null unless @state.show
|
@@ -58,7 +56,7 @@ class Lanes.Components.Modal extends Lanes.React.Component
|
|
58
56
|
button.eventKey ||= (button.key or button.title).toLowerCase()
|
59
57
|
<BS.Button key={button.title}
|
60
58
|
bsStyle={button.style || 'default'} className={name}
|
61
|
-
onClick={_.partial(@onButton, button)}>{button.title}</BS.Button>
|
59
|
+
onClick={_.partial(@onButton, _, button)}>{button.title}</BS.Button>
|
62
60
|
|
63
61
|
cls = _.classnames('lanes-modal', @state.className, @context.uistate?.layout_size)
|
64
62
|
Body = @state.body
|
@@ -68,7 +66,7 @@ class Lanes.Components.Modal extends Lanes.React.Component
|
|
68
66
|
</BS.Modal.Header>
|
69
67
|
|
70
68
|
<BS.Modal.Body style={maxHeight: @context.viewport.height - 250}>
|
71
|
-
<Body modal={@} />
|
69
|
+
<Body ref="body" {...@props} modal={@} />
|
72
70
|
</BS.Modal.Body>
|
73
71
|
|
74
72
|
<BS.Modal.Footer>{buttons}</BS.Modal.Footer>
|
@@ -49,7 +49,7 @@ class Lanes.Components.RecordFinder extends Lanes.React.Component
|
|
49
49
|
|
50
50
|
getValue: (ev) ->
|
51
51
|
value = if @props.parentModel
|
52
|
-
@props.parentModel[@props.associationName][@props.name]
|
52
|
+
@props.parentModel[@props.associationName]?[@props.name]
|
53
53
|
else
|
54
54
|
@props.model[@props.name]
|
55
55
|
value or ''
|
@@ -59,7 +59,7 @@ class Lanes.Components.RecordFinder extends Lanes.React.Component
|
|
59
59
|
# editOnly writable
|
60
60
|
model = @props.parentModel or @props.model
|
61
61
|
|
62
|
-
<BS.InputGroup>
|
62
|
+
<BS.InputGroup className="record-finder">
|
63
63
|
|
64
64
|
<BS.FormControl
|
65
65
|
{...props} {...handlers}
|
@@ -4,13 +4,15 @@
|
|
4
4
|
}
|
5
5
|
|
6
6
|
|
7
|
-
.record-finder-query-string {
|
8
|
-
text-transform: uppercase;
|
9
|
-
}
|
10
|
-
|
11
7
|
.record-finder {
|
12
8
|
.form-control {
|
13
|
-
|
9
|
+
@media print {
|
10
|
+
border-bottom-right-radius: $border-radius-base;
|
11
|
+
border-top-right-radius: $border-radius-base;
|
12
|
+
}
|
13
|
+
}
|
14
|
+
.input-group-btn {
|
15
|
+
@include hidden-print;
|
14
16
|
}
|
15
17
|
}
|
16
18
|
|
@@ -26,7 +26,7 @@ class Lanes.Components.FormGroup extends Lanes.React.Component
|
|
26
26
|
})
|
27
27
|
<BS.Col {...colProps} className={className}>
|
28
28
|
<BS.FormGroup className={valueClassNames}>
|
29
|
-
<
|
29
|
+
<BS.ControlLabel>{@props.label}</BS.ControlLabel>
|
30
30
|
{@props.children}
|
31
31
|
</BS.FormGroup>
|
32
32
|
</BS.Col>
|
@@ -1,4 +1,4 @@
|
|
1
|
-
class Lanes.Components.Icon extends Lanes.React.
|
1
|
+
class Lanes.Components.Icon extends Lanes.React.BaseComponent
|
2
2
|
|
3
3
|
propTypes:
|
4
4
|
type: React.PropTypes.string.isRequired
|
@@ -7,7 +7,8 @@ class Lanes.Components.Icon extends Lanes.React.Component
|
|
7
7
|
render: ->
|
8
8
|
|
9
9
|
classes = _.classnames 'icon', "icon-#{@props.type}", @props.className,
|
10
|
-
'
|
10
|
+
'non-printable': @props.noPrint,
|
11
|
+
'with-action' : @props.onClick,
|
11
12
|
"icon-#{@props.size}" : @props.size,
|
12
13
|
'icon-pulse' : @props.animated
|
13
14
|
'flush' : @props.flush
|
@@ -20,20 +20,16 @@ $lanes-field-margin: 6px;
|
|
20
20
|
}
|
21
21
|
|
22
22
|
}
|
23
|
-
|
24
23
|
&.align-right{
|
25
|
-
text-align: right;
|
26
24
|
.control-label, .value, .rw-widget input {text-align: right; }
|
27
25
|
}
|
28
26
|
&.align-center{
|
29
|
-
text-align: center;
|
30
27
|
.control-label, .value, .rw-widget input { text-align: center; }
|
31
28
|
}
|
32
29
|
|
33
30
|
&.select {
|
34
31
|
.form-control-feedback { right: 30px; }
|
35
32
|
}
|
36
|
-
|
37
33
|
.form-group {
|
38
34
|
background-color: rgba(255, 255, 255, 1);
|
39
35
|
transition: background-color 1000ms linear;
|
@@ -49,4 +45,9 @@ $lanes-field-margin: 6px;
|
|
49
45
|
background-color: darken($color-rgba, 20%);
|
50
46
|
}
|
51
47
|
}
|
48
|
+
|
49
|
+
.rw-datetimepicker {
|
50
|
+
&.rw-has-both { padding-right: 0; }
|
51
|
+
.rw-select { @include hidden-print; }
|
52
|
+
}
|
52
53
|
}
|
@@ -44,3 +44,21 @@
|
|
44
44
|
justify-content: center;
|
45
45
|
.progress { width: 100%; }
|
46
46
|
}
|
47
|
+
|
48
|
+
.icon {
|
49
|
+
&.with-action {
|
50
|
+
cursor: pointer;
|
51
|
+
&:hover{ text-shadow: 1px 2px 2px #666666; }
|
52
|
+
}
|
53
|
+
}
|
54
|
+
|
55
|
+
.lanes-panel-heading {
|
56
|
+
display: flex;
|
57
|
+
align-items: center;
|
58
|
+
.spacer {
|
59
|
+
flex: 1;
|
60
|
+
}
|
61
|
+
> *:not(.panel-title){
|
62
|
+
margin-left: 0.5rem;
|
63
|
+
}
|
64
|
+
}
|
data/client/lanes/index.js
CHANGED
File without changes
|
@@ -0,0 +1,13 @@
|
|
1
|
+
//= require ./namespace
|
2
|
+
//= require ./utilFunctions
|
3
|
+
//= require ./objToParam
|
4
|
+
//= require ./ModuleSupport
|
5
|
+
//= require ./loader
|
6
|
+
//= require ./MakeBaseClass
|
7
|
+
//= require ./el
|
8
|
+
//= require ./dom-polyfills
|
9
|
+
//= require ./dom
|
10
|
+
//= require ./format
|
11
|
+
//= require ./promise_helpers
|
12
|
+
//= require ./results
|
13
|
+
//= require ./ResizeSensor
|
data/client/lanes/lib/dom.coffee
CHANGED
@@ -66,7 +66,7 @@ _.dom = (unknown, query) ->
|
|
66
66
|
throw new TypeError("Selector / DOM node is not present")
|
67
67
|
else if _.isElement(unknown)
|
68
68
|
unknown
|
69
|
-
else if unknown.isReactComponent
|
69
|
+
else if unknown.isReactComponent or unknown.render
|
70
70
|
Lanes.Vendor.ReactDOM.findDOMNode(unknown)
|
71
71
|
else if unknown.nodeType is 9 # body tag
|
72
72
|
unknown
|
@@ -1,9 +1,9 @@
|
|
1
1
|
Lanes.u.format ||= {}
|
2
2
|
|
3
|
-
Lanes.u.format.
|
3
|
+
Lanes.u.format.shortDate = (d) ->
|
4
4
|
_.moment(d).format('L')
|
5
5
|
|
6
|
-
Lanes.u.format.
|
6
|
+
Lanes.u.format.shortDateTime = (d) ->
|
7
7
|
_.moment(d).format('lll')
|
8
8
|
|
9
9
|
Lanes.u.format.currency = (v) ->
|
@@ -1,16 +1,4 @@
|
|
1
|
-
//=
|
2
|
-
//= require ./namespace
|
3
|
-
//= require ./utilFunctions
|
4
|
-
//= require ./objToParam
|
5
|
-
//= require ./ModuleSupport
|
6
|
-
//= require ./loader
|
7
|
-
//= require ./MakeBaseClass
|
8
|
-
//= require ./el
|
9
|
-
//= require ./dom-polyfills
|
10
|
-
//= require ./dom
|
11
|
-
//= require ./format
|
12
|
-
//= require ./promise_helpers
|
13
|
-
//= require ./results
|
1
|
+
//=require ./all
|
14
2
|
<% if Lanes.env.development?
|
15
3
|
require_asset "./development"
|
16
4
|
else
|
@@ -2,7 +2,7 @@
|
|
2
2
|
#
|
3
3
|
GECKO = /Gecko\//.test(navigator.userAgent)
|
4
4
|
|
5
|
-
class
|
5
|
+
class Lanes.lib.AssetLoader
|
6
6
|
|
7
7
|
constructor: (urls, cb) ->
|
8
8
|
finished = 0
|
@@ -91,7 +91,7 @@ Lanes.lib.RequestAssets = (urls...) ->
|
|
91
91
|
for url, i in urls
|
92
92
|
urls[i] = Lanes.config.assets_path_prefix.concat( '/', urls[i] )
|
93
93
|
new _.Promise( (resolve, reject) ->
|
94
|
-
new
|
94
|
+
new Lanes.lib.AssetLoader(urls, (completed) ->
|
95
95
|
failures = _.pick(completed, (status, url) -> !status.success )
|
96
96
|
if _.isEmpty(failures)
|
97
97
|
resolve(completed)
|
@@ -122,6 +122,8 @@ lcDash = (char, match, index) ->
|
|
122
122
|
|
123
123
|
originalTitleize = _.titleize
|
124
124
|
|
125
|
+
|
126
|
+
# some are taken from https://github.com/epeli/underscore.string
|
125
127
|
_.mixin({
|
126
128
|
dasherize: (str) ->
|
127
129
|
_.trim(str).replace(/([A-Z])/g, lcDash).replace(/[-_\s]+/g, '-').toLowerCase()
|
@@ -144,6 +146,16 @@ _.mixin({
|
|
144
146
|
isPromise: (obj) ->
|
145
147
|
!!obj && (_.isObject(obj) || _.isFunction(obj)) && _.isFunction(obj.then)
|
146
148
|
|
149
|
+
classify: (str) ->
|
150
|
+
s = _.toString(str)
|
151
|
+
@capitalize(@camelCase(s.replace(/[\W_]/g, ' ')).replace(/\s/g, ''))
|
152
|
+
|
153
|
+
humanize: (str) ->
|
154
|
+
@capitalize(@trim(@underscored(str).replace(/_id$/, '').replace(/_/g, ' ')))
|
155
|
+
|
156
|
+
underscored: (str) ->
|
157
|
+
return @trim(str).replace(/([a-z\d])([A-Z]+)/g, '$1_$2').replace(/[-\s]+/g, '_').toLowerCase()
|
158
|
+
|
147
159
|
isBlank: (value) ->
|
148
160
|
switch true
|
149
161
|
when _.isDate(value)
|
@@ -4,7 +4,7 @@
|
|
4
4
|
# Note! An AssociationMap is created for each type of Model, and #
|
5
5
|
# is shared between all instances #
|
6
6
|
# ------------------------------------------------------------------ #
|
7
|
-
class Lanes.Models.
|
7
|
+
class Lanes.Models.AssociationMap
|
8
8
|
constructor: (@klass) ->
|
9
9
|
@klass::derived ||= {}
|
10
10
|
@definitions = @klass::associations
|
@@ -45,6 +45,8 @@ class Lanes.Models.AssocationMap
|
|
45
45
|
getOptions: (name, model) ->
|
46
46
|
definition = @definitions[name]
|
47
47
|
options = { parent: model }
|
48
|
+
if definition.inverse
|
49
|
+
options[ definition.inverse.name ] = model
|
48
50
|
if definition.options
|
49
51
|
_.extend(options, Lanes.u.resultsFor(model, definition.options))
|
50
52
|
options
|
@@ -131,27 +133,34 @@ class Lanes.Models.AssocationMap
|
|
131
133
|
continue if not @exists(name) or
|
132
134
|
(_.isEmpty(value) and not @isCreated(model, name))
|
133
135
|
|
134
|
-
|
136
|
+
definition = @definitions[name]
|
135
137
|
|
136
|
-
if
|
137
|
-
association
|
138
|
+
if @isCreated(model, name)
|
139
|
+
association = model[name]
|
140
|
+
# nothing to do if setting to same object
|
141
|
+
continue if value is association
|
138
142
|
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
else
|
145
|
-
model.set(this.pk(name), value.id, options) if value.id
|
146
|
-
if Lanes.u.isModel(value)
|
147
|
-
@replace(model, name, value)
|
143
|
+
if association.isProxy and Lanes.u.isModel(value) and not value.isProxy
|
144
|
+
association.replaceWithModel(value, association_name: name)
|
145
|
+
else if definition.model
|
146
|
+
if value
|
147
|
+
@_setModel(model, name, value, options, fn_name)
|
148
148
|
else
|
149
|
-
association
|
150
|
-
|
151
|
-
|
152
|
-
model.trigger("change:#{name}", value, {})
|
149
|
+
association.clear()
|
150
|
+
else
|
151
|
+
if value then association[fn_name]( value, options ) else association.clear()
|
153
152
|
else
|
154
|
-
|
153
|
+
@_setModel(model, name, value, options, fn_name)
|
154
|
+
|
155
|
+
_setModel: (model, name, value, options, fn_name) ->
|
156
|
+
model.set(this.pk(name), value.id, options) if value.id
|
157
|
+
|
158
|
+
if Lanes.u.isModel(value)
|
159
|
+
@replace(model, name, value)
|
160
|
+
else
|
161
|
+
model[name][fn_name]( value )
|
162
|
+
if options?.silent isnt true
|
163
|
+
model.trigger("change:#{name}", value, {})
|
155
164
|
|
156
165
|
pk: (name) ->
|
157
166
|
def = @definitions[name]
|
@@ -20,6 +20,9 @@ class BaseModel
|
|
20
20
|
deps: ['invalidAttributes'], fn: ->
|
21
21
|
_.isEmpty @invalidAttributes #_calculateInvalidAttributes()
|
22
22
|
|
23
|
+
hasErrors:
|
24
|
+
deps: ['errors'], fn: -> not _.isEmpty(@errors)
|
25
|
+
|
23
26
|
errorMessage:
|
24
27
|
deps:['errors'], fn: ->
|
25
28
|
if !@errors then ''
|
@@ -198,9 +201,14 @@ class BaseModel
|
|
198
201
|
data = this.getAttributes(props:true, true)
|
199
202
|
else
|
200
203
|
data = this.unsavedAttributes()
|
201
|
-
if this.associations &&
|
202
|
-
|
203
|
-
|
204
|
+
if this.associations && !options.excludeAssociations
|
205
|
+
# empty associations are not included
|
206
|
+
associationData = this.associations.dataForSave(this, options)
|
207
|
+
_.extend(data, associationData)
|
208
|
+
# if submitting associations, we must include our id so they can be updated
|
209
|
+
unless this.isNew() or _.isEmpty(associationData)
|
210
|
+
data[@idAttribute] = this.getId()
|
211
|
+
|
204
212
|
data
|
205
213
|
|
206
214
|
unCacheDerived: (name) ->
|
@@ -255,7 +263,7 @@ class BaseModel
|
|
255
263
|
klass::session['updated_at'] ||= 'date'
|
256
264
|
|
257
265
|
if klass::associations
|
258
|
-
klass::associations = new Lanes.Models.
|
266
|
+
klass::associations = new Lanes.Models.AssociationMap(klass)
|
259
267
|
|
260
268
|
@afterExtended: (klass) ->
|
261
269
|
return if klass::abstractClass
|
@@ -123,7 +123,9 @@ class ModelsCollection
|
|
123
123
|
|
124
124
|
# true if any models have unsaved data
|
125
125
|
isDirty: ->
|
126
|
-
|
126
|
+
!!@find( (model) ->
|
127
|
+
_.result(model, 'isDirty') isnt false
|
128
|
+
)
|
127
129
|
|
128
130
|
url: -> @model::urlRoot()
|
129
131
|
|
@@ -140,8 +142,8 @@ class ModelsCollection
|
|
140
142
|
dataForSave: (options) ->
|
141
143
|
unsaved = []
|
142
144
|
for model in @models
|
143
|
-
if options.saveAll || model.isDirty
|
144
|
-
unsaved.push( model.dataForSave(options) )
|
145
|
+
if options.saveAll || model.isDirty isnt false
|
146
|
+
unsaved.push( model.dataForSave?(options) or model.serialize())
|
145
147
|
unsaved
|
146
148
|
|
147
149
|
mixins:[
|