lanes 0.6.1 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/client/lanes/Config.coffee +26 -9
- data/client/lanes/access/screens/user-management/UserManagement.cjsx +1 -1
- data/client/lanes/components/grid/EditingMixin.cjsx +8 -4
- data/client/lanes/components/grid/PopOverMixin.cjsx +7 -1
- data/client/lanes/components/modal/Modal.cjsx +11 -1
- data/client/lanes/components/record-finder/RecordFinder.cjsx +8 -4
- data/client/lanes/components/shared/DateTime.cjsx +8 -6
- data/client/lanes/components/shared/FieldMixin.cjsx +3 -3
- data/client/lanes/components/shared/Icon.cjsx +1 -1
- data/client/lanes/components/shared/ImageAsset.cjsx +23 -11
- data/client/lanes/components/shared/NetworkActivityOverlay.cjsx +2 -0
- data/client/lanes/extension/Base.coffee +2 -0
- data/client/lanes/fonts/fontawesome-webfont.woff +0 -0
- data/client/lanes/fonts/fontawesome-webfont.woff2 +0 -0
- data/client/lanes/lib/RequestAssets.coffee +30 -0
- data/client/lanes/lib/all.js +1 -0
- data/client/lanes/lib/loader.js +93 -0
- data/client/lanes/lib/utilFunctions.coffee +12 -0
- data/client/lanes/models/Asset.coffee +3 -4
- data/client/lanes/models/AssociationMap.coffee +17 -6
- data/client/lanes/models/Base.coffee +20 -13
- data/client/lanes/models/Collection.coffee +4 -1
- data/client/lanes/models/PubSub.coffee +2 -3
- data/client/lanes/models/SmtpSettings.coffee +7 -0
- data/client/lanes/models/Sync.coffee +2 -2
- data/client/lanes/react/Viewport.coffee +14 -10
- data/client/lanes/react/mixins/FieldErrors.coffee +3 -4
- data/client/lanes/react/mixins/ReadEditingState.coffee +1 -0
- data/client/lanes/remote/Bootstrap.coffee +85 -0
- data/client/lanes/remote/api.coffee +2 -1
- data/client/lanes/remote/onDocumentReady.coffee +12 -0
- data/client/lanes/screens/Definitions.coffee +29 -12
- data/client/lanes/screens/SystemSettings.cjsx +12 -3
- data/client/lanes/styles/fonts/_bordered-pulled.scss +9 -0
- data/client/lanes/styles/fonts/_core.scss +1 -2
- data/client/lanes/styles/fonts/_icons.scss +56 -0
- data/client/lanes/styles/fonts/_mixins.scss +37 -4
- data/client/lanes/styles/fonts/_path.scss +2 -2
- data/client/lanes/styles/fonts/_screen-reader.scss +5 -0
- data/client/lanes/styles/fonts/_variables.scss +58 -2
- data/client/lanes/styles/fonts/font-awesome.scss +3 -1
- data/client/lanes/vendor/development/calendar.js +56 -57
- data/client/lanes/vendor/development/commons.js +31319 -29618
- data/client/lanes/vendor/development/data.js +8468 -7607
- data/client/lanes/vendor/development/helpers.js +265 -131
- data/client/lanes/vendor/development/toggle.js +288 -184
- data/client/lanes/vendor/development/ui.js +3387 -3492
- data/client/lanes/vendor/development/widgets.js +972 -1229
- data/client/lanes/vendor/production/calendar.js +60 -61
- data/client/lanes/vendor/production/commons.js +30695 -29032
- data/client/lanes/vendor/production/data.js +8457 -7598
- data/client/lanes/vendor/production/toggle.js +288 -184
- data/client/lanes/vendor/production/ui.js +3264 -3373
- data/client/lanes/vendor/production/widgets.js +972 -1229
- data/client/lanes/vendor/standalone/index.js +21106 -18761
- data/client/lanes/vendor/styles/toggle.scss +4 -3
- data/client/lanes/workspace/ScreenView.cjsx +2 -2
- data/client/lanes/workspace/styles/header.scss +4 -0
- data/config/routes.rb +0 -2
- data/db/migrate/01_create_system_settings.rb +1 -1
- data/db/migrate/02_create_assets.rb +1 -1
- data/lanes.gemspec +1 -0
- data/lib/lanes.rb +1 -0
- data/lib/lanes/access/track_modifications.rb +4 -2
- data/lib/lanes/api.rb +1 -0
- data/lib/lanes/api/cable.rb +11 -3
- data/lib/lanes/api/controller_base.rb +23 -19
- data/lib/lanes/api/default_routes.rb +9 -1
- data/lib/lanes/api/generic_controller.rb +1 -1
- data/lib/lanes/api/handlers/asset.rb +2 -3
- data/lib/lanes/api/helper_methods.rb +5 -11
- data/lib/lanes/api/pub_sub.rb +13 -7
- data/lib/lanes/api/request_wrapper.rb +1 -1
- data/lib/lanes/api/routing.rb +10 -7
- data/lib/lanes/api/to_json.rb +7 -0
- data/lib/lanes/asset.rb +4 -1
- data/lib/lanes/concerns/set_attribute_data.rb +2 -1
- data/lib/lanes/extension.rb +3 -1
- data/lib/lanes/mailer.rb +40 -0
- data/lib/lanes/rake_tasks.rb +4 -0
- data/lib/lanes/spec_helper.rb +11 -3
- data/lib/lanes/system_settings.rb +22 -9
- data/lib/lanes/version.rb +1 -1
- data/lib/lanes/workspace/extension.rb +5 -0
- data/npm-build/package.json +2 -2
- data/npm-build/react-toggle.js +1 -1
- data/npm-build/standalone.js +3 -0
- data/spec/command-reference-files/initial/Gemfile +1 -1
- data/spec/command-reference-files/initial/client/appy-app/Extension.coffee +2 -1
- data/spec/command-reference-files/model/db/migrate/20150218032025_create_test_tests.rb +1 -1
- data/spec/command-reference-files/screen/client/appy-app/Extension.coffee +2 -1
- data/spec/fixtures/system_settings.yml +8 -1
- data/spec/server/mailer_spec.rb +33 -0
- data/spec/server/system_settings_spec.rb +16 -0
- data/templates/client/Extension.coffee +2 -1
- data/templates/config/database.yml +1 -1
- data/templates/db/create_table_migration.rb +1 -1
- metadata +27 -6
- data/client/fonts/fontawesome-webfont.woff +0 -0
- data/client/fonts/fontawesome-webfont.woff2 +0 -0
- data/client/lanes/lib/loader.coffee +0 -100
- data/client/lanes/workspace/Modal.cjsx +0 -47
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 16b8badf6014b9cc559daad0046bffa56d08e791
|
4
|
+
data.tar.gz: b0018988b0ef191d183965f06ace441c7875b073
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ddbc32e5e1dd43e8ca84e27e2a1bd02117dab786ab085900288990de9e32c7bfa406ffb23b3c32c7cb48a8c6da1c404f71f49b7064372b23bdfe922591de83a3
|
7
|
+
data.tar.gz: 2e4d091cfa1abcf667cf59dde4384f88c885825f436b7dd746528d9d5316f00ec3427db1cbb02176230bf9458d164d0dcaada35e1042ecf790dad3f83ba16a0c
|
data/client/lanes/Config.coffee
CHANGED
@@ -7,17 +7,20 @@ class SystemSettings extends Lanes.Models.Base
|
|
7
7
|
settings: "object"
|
8
8
|
|
9
9
|
associations:
|
10
|
-
logo:
|
10
|
+
logo: { model: "Lanes.Models.Asset" }
|
11
|
+
smtp: { model: "Lanes.Models.SmtpSettings" }
|
12
|
+
print_logo: { model: "Lanes.Models.Asset" }
|
11
13
|
|
12
14
|
modelTypeIdentifier: -> 'system-settings'
|
13
15
|
url: -> Lanes.config.api_path + '/system-settings'
|
14
16
|
initialize: ->
|
15
17
|
@on('change:settings', @setDefaultSettings)
|
18
|
+
@smtp.set(@settings?.lanes?.smtp)
|
16
19
|
@setDefaultSettings()
|
17
20
|
|
18
21
|
setDefaultSettings: ->
|
19
22
|
@settings ||= {}
|
20
|
-
@settings.lanes
|
23
|
+
@settings.lanes ||= {}
|
21
24
|
|
22
25
|
forExtension: (ext) ->
|
23
26
|
@settings[ext] ||= {}
|
@@ -25,17 +28,27 @@ class SystemSettings extends Lanes.Models.Base
|
|
25
28
|
setValueForExtension: (ext, key, value) ->
|
26
29
|
@forExtension(ext)[key] = value
|
27
30
|
|
31
|
+
set: (data) ->
|
32
|
+
ret = super
|
33
|
+
@smtp.set(@settings?.lanes?.smtp)
|
34
|
+
ret
|
35
|
+
|
36
|
+
dataForSave: ->
|
37
|
+
data = super
|
38
|
+
data.settings.lanes.smtp = @smtp.serialize()
|
39
|
+
data
|
40
|
+
|
28
41
|
class Config extends Lanes.Models.State
|
29
42
|
|
30
43
|
session:
|
31
|
-
csrf_token: { type: 'string', setOnce: true
|
32
|
-
root_path: { type: 'string', setOnce: true
|
33
|
-
api_path: { type: 'string', default: '/api'
|
34
|
-
|
35
|
-
environment: { type: 'string', setOnce: true }
|
44
|
+
csrf_token: { type: 'string', setOnce: true }
|
45
|
+
root_path: { type: 'string', setOnce: true }
|
46
|
+
api_path: { type: 'string', default: '/api' }
|
47
|
+
environment: { type: 'string', setOnce: true }
|
36
48
|
system_settings: { type: 'state', required: true }
|
37
49
|
assets_path_prefix: { type: 'string', setOnce: true }
|
38
|
-
|
50
|
+
api_host: { type: 'string', default: "//#{window.location.host }" }
|
51
|
+
initial_workspace_screen_id: { type: 'string', setOnce: true }
|
39
52
|
|
40
53
|
derived:
|
41
54
|
env:
|
@@ -56,4 +69,8 @@ class Config extends Lanes.Models.State
|
|
56
69
|
@set(options)
|
57
70
|
Lanes.Extensions.setBootstrapData(options) if _.isObject(options)
|
58
71
|
|
59
|
-
|
72
|
+
configInstance = new Config
|
73
|
+
|
74
|
+
Object.defineProperty Lanes, 'config',
|
75
|
+
get: -> configInstance
|
76
|
+
set: -> throw new Error("Unable to reset config")
|
@@ -14,15 +14,19 @@ Lanes.Components.Grid.EditingMixin = {
|
|
14
14
|
React.PropTypes.bool, React.PropTypes.func
|
15
15
|
])
|
16
16
|
|
17
|
+
cleanProps: (props) ->
|
18
|
+
_.omit(props, 'index', 'field', 'props', 'query', 'rowIndex')
|
19
|
+
|
17
20
|
editorTypes:
|
18
21
|
text: (props) ->
|
19
|
-
props
|
20
|
-
|
22
|
+
inputProps = _.omit(@cleanProps(props), 'model')
|
23
|
+
inputProps.value ?= ''
|
24
|
+
<input type="text" {...inputProps}
|
21
25
|
onChange={_.partial(@onFieldChange, _, props.field)} />
|
22
26
|
bigdec: (props) ->
|
23
|
-
<LC.NumberInput unstyled {
|
27
|
+
<LC.NumberInput unstyled {...@cleanProps(props)} />
|
24
28
|
date: (props) ->
|
25
|
-
<LC.DateTime {
|
29
|
+
<LC.DateTime {...@cleanProps(props)} inputOnly step={15}
|
26
30
|
onChange={_.partial(@onDateFieldChange, _, props.field)} />
|
27
31
|
|
28
32
|
displayTypes:
|
@@ -1,5 +1,9 @@
|
|
1
1
|
##= require ./EditingMixin
|
2
|
-
|
2
|
+
BAD_PROPS = [
|
3
|
+
'position', 'model', 'index', 'syncImmediatly', 'query',
|
4
|
+
'onCancel', 'onSave', 'cellStyles', 'editors', 'rowIndex',
|
5
|
+
'rowHeight', 'allowDelete'
|
6
|
+
]
|
3
7
|
Lanes.Components.Grid.PopoverMixin = {
|
4
8
|
|
5
9
|
mixins: [
|
@@ -25,6 +29,8 @@ Lanes.Components.Grid.PopoverMixin = {
|
|
25
29
|
props.arrowOffsetTop = Math.min(position.top + 20, (props.height - 75))
|
26
30
|
props.positionTop = Math.max(5, position.top - props.arrowOffsetTop + (position.rowHeight / 2))
|
27
31
|
|
32
|
+
props = _.omit(props, BAD_PROPS)
|
33
|
+
|
28
34
|
<div className="editor po">
|
29
35
|
<BS.Popover
|
30
36
|
id="editing-form"
|
@@ -25,6 +25,12 @@ class Lanes.Components.Modal extends Lanes.React.Component
|
|
25
25
|
getInitialState: ->
|
26
26
|
show: false
|
27
27
|
|
28
|
+
setBusy: (isBusy) ->
|
29
|
+
@setState({isBusy})
|
30
|
+
|
31
|
+
busyMessage: ->
|
32
|
+
(if _.isString(@state.isBusy) then @state.isBusy else '') + '…'
|
33
|
+
|
28
34
|
onOkButton: (ev) -> @state.onOk?(this, ev)
|
29
35
|
onCancelButton: (ev) -> @state.onCancel?(this, ev)
|
30
36
|
onButton: (ev, btn) ->
|
@@ -56,7 +62,9 @@ class Lanes.Components.Modal extends Lanes.React.Component
|
|
56
62
|
button.eventKey ||= (button.key or button.title).toLowerCase()
|
57
63
|
<BS.Button key={button.title}
|
58
64
|
bsStyle={button.style || 'default'} className={name}
|
59
|
-
|
65
|
+
disabled={!!@state.isBusy}
|
66
|
+
onClick={_.partial(@onButton, _, button)}
|
67
|
+
>{button.title}</BS.Button>
|
60
68
|
|
61
69
|
cls = _.classnames('lanes-modal', @state.className, @context.uistate?.layout_size)
|
62
70
|
Body = @state.body
|
@@ -74,6 +82,8 @@ class Lanes.Components.Modal extends Lanes.React.Component
|
|
74
82
|
</BS.Modal.Header>
|
75
83
|
|
76
84
|
<BS.Modal.Body style={maxHeight: @context.viewport.height - 250}>
|
85
|
+
<LC.NetworkActivityOverlay visible={!!@state.isBusy}
|
86
|
+
message={@busyMessage()} />
|
77
87
|
<Body {...@props} modal={@} />
|
78
88
|
</BS.Modal.Body>
|
79
89
|
|
@@ -8,8 +8,13 @@ class Lanes.Components.RecordFinder extends Lanes.React.Component
|
|
8
8
|
parentModel: Lanes.PropTypes.State
|
9
9
|
commands: React.PropTypes.object
|
10
10
|
onModelSet: React.PropTypes.func
|
11
|
+
autoFocus: React.PropTypes.bool
|
12
|
+
inputType: React.PropTypes.string
|
11
13
|
associationName: React.PropTypes.string
|
12
14
|
|
15
|
+
getDefaultProps: ->
|
16
|
+
inputType: 'text'
|
17
|
+
|
13
18
|
mixins: [
|
14
19
|
Lanes.Components.Form.InputFieldMixin
|
15
20
|
]
|
@@ -63,15 +68,14 @@ class Lanes.Components.RecordFinder extends Lanes.React.Component
|
|
63
68
|
|
64
69
|
renderInputField: (props, handlers) ->
|
65
70
|
model = @props.parentModel or @props.model
|
66
|
-
|
67
71
|
<BS.InputGroup className="record-finder">
|
68
|
-
<
|
69
|
-
{
|
72
|
+
<input className="form-control"
|
73
|
+
type={@props.inputType}
|
74
|
+
autoFocus={@props.autoFocus}
|
70
75
|
onChange={@fieldMixinSetValue}
|
71
76
|
value={@getValue()}
|
72
77
|
onKeyPress={@onKeyPress}
|
73
78
|
/>
|
74
|
-
|
75
79
|
<BS.InputGroup.Button>
|
76
80
|
<button className='btn btn-primary' onClick={@showFinder}>
|
77
81
|
<LC.Icon lg
|
@@ -16,20 +16,22 @@ class Lanes.Components.DateTime extends Lanes.React.Component
|
|
16
16
|
handleKeyDown: (ev) ->
|
17
17
|
@props.onEnter() if ev.key is 'Enter'
|
18
18
|
|
19
|
-
handleDateTimeChange: (val) ->
|
20
|
-
@fieldMixinSetValue({target: {value: val}})
|
21
|
-
|
22
|
-
|
23
19
|
renderDisplay: (props) ->
|
24
20
|
clean = LC.Form.FieldMixin.statics.cleanSizeProps(props)
|
25
21
|
<BS.FormControl.Static {...clean}>
|
26
|
-
{
|
22
|
+
{@getDateValue().format(this.props.format)}
|
27
23
|
</BS.FormControl.Static>
|
28
24
|
|
25
|
+
getDateValue: ->
|
26
|
+
_.moment.utc(@fieldMixinGetValue())
|
27
|
+
|
28
|
+
handleDateTimeChange: (val) ->
|
29
|
+
@fieldMixinSetValue({target: {value: Lanes.u.utcToLocalDate(val)}})
|
30
|
+
|
29
31
|
renderEdit: (props) ->
|
30
32
|
props = _.extend({
|
31
33
|
ref: 'control'
|
32
|
-
value: @
|
34
|
+
value: Lanes.u.dateToUTC(@getDateValue().toDate())
|
33
35
|
onChange: @handleDateTimeChange
|
34
36
|
}, @props)
|
35
37
|
props = _.omit(LC.Form.FieldMixin.statics.cleanSizeProps(props), 'writable')
|
@@ -1,4 +1,4 @@
|
|
1
|
-
Lanes.Components.Form
|
1
|
+
Lanes.Components.Form ||= {}
|
2
2
|
|
3
3
|
|
4
4
|
Lanes.Components.Form.FieldMixin = {
|
@@ -152,9 +152,9 @@ Lanes.Components.Form.FieldMixin = {
|
|
152
152
|
'has-error': hasError
|
153
153
|
}
|
154
154
|
)
|
155
|
-
|
155
|
+
fieldProps = Lanes.u.cleanBsSizes(props)
|
156
156
|
field = (@[ "render#{method}" ] || @["_fieldMixinRender#{method}"])(
|
157
|
-
if @props.fieldOnly then
|
157
|
+
if @props.fieldOnly then fieldProps else _.omit(fieldProps, 'className')
|
158
158
|
)
|
159
159
|
if @props.fieldOnly
|
160
160
|
field
|
@@ -34,7 +34,7 @@ class Lanes.Components.Icon extends Lanes.React.BaseComponent
|
|
34
34
|
'clickable' : @props.clickable or (@props.tooltip and @props.tooltipProps.trigger is 'click')
|
35
35
|
|
36
36
|
icon =
|
37
|
-
<i style={@props.style} className={classes} />
|
37
|
+
<i style={@props.style} className={classes} onClick={@props.onClick} />
|
38
38
|
|
39
39
|
if @props.tooltip
|
40
40
|
props = _.extend({}, DEFAULT_TOOLTIP_PROPS, @props.tooltipProps)
|
@@ -2,6 +2,7 @@ class Lanes.Components.ImageAsset extends Lanes.React.Component
|
|
2
2
|
|
3
3
|
propTypes:
|
4
4
|
asset: Lanes.PropTypes.Model.isRequired
|
5
|
+
label: React.PropTypes.string
|
5
6
|
size: React.PropTypes.oneOf([
|
6
7
|
'thumb', 'medium', 'original'
|
7
8
|
]).isRequired
|
@@ -11,8 +12,9 @@ class Lanes.Components.ImageAsset extends Lanes.React.Component
|
|
11
12
|
|
12
13
|
listenNetworkEvents: true
|
13
14
|
|
14
|
-
|
15
|
-
|
15
|
+
mixins: [
|
16
|
+
Lanes.React.Mixins.ReadEditingState
|
17
|
+
]
|
16
18
|
|
17
19
|
handleImageChange: (ev) ->
|
18
20
|
ev.preventDefault()
|
@@ -24,8 +26,25 @@ class Lanes.Components.ImageAsset extends Lanes.React.Component
|
|
24
26
|
blankImage: ->
|
25
27
|
null
|
26
28
|
|
29
|
+
Label: ->
|
30
|
+
return null unless @props.label
|
31
|
+
<label>{@props.label}</label>
|
32
|
+
|
33
|
+
Edit: ->
|
34
|
+
return null unless @isEditingRecord()
|
35
|
+
<form>
|
36
|
+
<label className="selector">
|
37
|
+
<span>
|
38
|
+
{if @asset.isPresent then 'Change' else 'Add'}
|
39
|
+
</span>
|
40
|
+
<input id='file' className="file" type="file"
|
41
|
+
onChange={@handleImageChange} />
|
42
|
+
</label>
|
43
|
+
</form>
|
44
|
+
|
27
45
|
render: ->
|
28
46
|
Component = if @asset.hasImage then @renderImage else @blankImage
|
47
|
+
|
29
48
|
className = _.classnames('image-asset', @props.className, {
|
30
49
|
'with-image': @asset.hasImage
|
31
50
|
})
|
@@ -33,14 +52,7 @@ class Lanes.Components.ImageAsset extends Lanes.React.Component
|
|
33
52
|
{...Lanes.u.bsSizes(@props)}
|
34
53
|
className={className}
|
35
54
|
>
|
55
|
+
<@Label />
|
36
56
|
<Component />
|
37
|
-
|
38
|
-
<label className="selector">
|
39
|
-
<span>
|
40
|
-
{if @asset.isPresent then 'Change' else 'Add'}
|
41
|
-
</span>
|
42
|
-
<input id='file' className="file" type="file"
|
43
|
-
onChange={@handleImageChange} />
|
44
|
-
</label>
|
45
|
-
</form>
|
57
|
+
<@Edit />
|
46
58
|
</BS.Col>
|
Binary file
|
Binary file
|
@@ -0,0 +1,30 @@
|
|
1
|
+
class Lanes.lib.AssetLoader
|
2
|
+
|
3
|
+
constructor: (urls, cb) ->
|
4
|
+
finished = 0
|
5
|
+
completed = {}
|
6
|
+
onComplete = (url, success, error = false) ->
|
7
|
+
finished += 1
|
8
|
+
completed[url] = { success: success == true, error: error }
|
9
|
+
cb(completed) if finished == urls.length
|
10
|
+
|
11
|
+
for baseUrl in urls
|
12
|
+
url = "#{baseUrl}?#{parseInt(Math.random() * 100000)}"
|
13
|
+
if /.css($|\?)/.test(url)
|
14
|
+
Lanes.lib.loader.css(url, onComplete)
|
15
|
+
else
|
16
|
+
Lanes.lib.loader.js(url, onComplete)
|
17
|
+
|
18
|
+
Lanes.lib.RequestAssets = (urls...) ->
|
19
|
+
urls = urls[0] if urls.length == 1 && _.isArray(urls[0])
|
20
|
+
new _.Promise( (resolve, reject) ->
|
21
|
+
|
22
|
+
new Lanes.lib.AssetLoader(urls, (completed) ->
|
23
|
+
failures = _.pick(completed, (status, url) -> !status.success )
|
24
|
+
if _.isEmpty(failures)
|
25
|
+
resolve(completed)
|
26
|
+
else
|
27
|
+
Lanes.warn( _.keys(failures).join(',') + " failed to load" )
|
28
|
+
reject( failures )
|
29
|
+
)
|
30
|
+
)
|
data/client/lanes/lib/all.js
CHANGED
@@ -0,0 +1,93 @@
|
|
1
|
+
//= require ./namespace
|
2
|
+
|
3
|
+
// https://pie.gd/test/script-link-events/
|
4
|
+
|
5
|
+
(function( w ){
|
6
|
+
var insertBefore = function(){
|
7
|
+
var refs = doc.getElementsByTagName( "head" )[ 0 ].childNodes;
|
8
|
+
return refs[ refs.length - 1];
|
9
|
+
};
|
10
|
+
|
11
|
+
var doc = w.document;
|
12
|
+
|
13
|
+
// https://github.com/filamentgroup/loadJS/blob/master/loadJS.js
|
14
|
+
var loadJS = function( src, cb ){
|
15
|
+
"use strict";
|
16
|
+
var ref = insertBefore();
|
17
|
+
var script = doc.createElement( "script" );
|
18
|
+
script.src = src;
|
19
|
+
script.async = true;
|
20
|
+
ref.parentNode.insertBefore( script, ref );
|
21
|
+
if (cb && typeof(cb) === "function") {
|
22
|
+
script.onload = function(ev){
|
23
|
+
cb(script, ev);
|
24
|
+
}
|
25
|
+
}
|
26
|
+
return script;
|
27
|
+
};
|
28
|
+
|
29
|
+
|
30
|
+
// https://github.com/filamentgroup/loadCSS/blob/master/src/loadCSS.js
|
31
|
+
var loadCSS = function( href, cb){
|
32
|
+
var ss = doc.createElement( "link" );
|
33
|
+
var ref = insertBefore();
|
34
|
+
|
35
|
+
var sheets = doc.styleSheets;
|
36
|
+
ss.rel = "stylesheet";
|
37
|
+
ss.href = href;
|
38
|
+
ss.media = "only x";
|
39
|
+
|
40
|
+
// wait until body is defined before injecting link. This ensures a non-blocking load in IE11.
|
41
|
+
function ready( cb ){
|
42
|
+
if( doc.body ){
|
43
|
+
return cb();
|
44
|
+
}
|
45
|
+
setTimeout(function(){
|
46
|
+
ready( cb );
|
47
|
+
});
|
48
|
+
}
|
49
|
+
// Inject link
|
50
|
+
// Note: the ternary preserves the existing behavior of "before" argument, but we could choose to change the argument to "after" in a later release and standardize on ref.nextSibling for all refs
|
51
|
+
// Note: `insertBefore` is used instead of `appendChild`, for safety re: http://www.paulirish.com/2011/surefire-dom-element-insertion/
|
52
|
+
ready( function(){
|
53
|
+
ref.parentNode.insertBefore( ss, ref.nextSibling );
|
54
|
+
});
|
55
|
+
// A method (exposed on return object for external use) that mimics onload by polling document.styleSheets until it includes the new sheet.
|
56
|
+
var onloadcssdefined = function( cb ){
|
57
|
+
var resolvedHref = ss.href;
|
58
|
+
var i = sheets.length;
|
59
|
+
while( i-- ){
|
60
|
+
if( sheets[ i ].href === resolvedHref ){
|
61
|
+
return cb(sheets[i]);
|
62
|
+
}
|
63
|
+
}
|
64
|
+
setTimeout(function() {
|
65
|
+
onloadcssdefined( cb );
|
66
|
+
});
|
67
|
+
};
|
68
|
+
|
69
|
+
function loadCB(ev){
|
70
|
+
if( ss.addEventListener ){
|
71
|
+
ss.removeEventListener( "load", loadCB );
|
72
|
+
}
|
73
|
+
ss.media = "all";
|
74
|
+
if (cb && typeof(cb) === "function") {
|
75
|
+
cb(ss, ev);
|
76
|
+
}
|
77
|
+
}
|
78
|
+
|
79
|
+
// once loaded, set link's media back to `all` so that the stylesheet applies once it loads
|
80
|
+
if( ss.addEventListener ){
|
81
|
+
ss.addEventListener( "load", loadCB);
|
82
|
+
} else {
|
83
|
+
onloadcssdefined( loadCB );
|
84
|
+
}
|
85
|
+
return ss;
|
86
|
+
};
|
87
|
+
|
88
|
+
w.Lanes.lib.loader = {
|
89
|
+
js: loadJS,
|
90
|
+
css: loadCSS
|
91
|
+
};
|
92
|
+
|
93
|
+
}( typeof global !== "undefined" ? global : this ));
|