lanes 0.6.1 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (103) hide show
  1. checksums.yaml +4 -4
  2. data/client/lanes/Config.coffee +26 -9
  3. data/client/lanes/access/screens/user-management/UserManagement.cjsx +1 -1
  4. data/client/lanes/components/grid/EditingMixin.cjsx +8 -4
  5. data/client/lanes/components/grid/PopOverMixin.cjsx +7 -1
  6. data/client/lanes/components/modal/Modal.cjsx +11 -1
  7. data/client/lanes/components/record-finder/RecordFinder.cjsx +8 -4
  8. data/client/lanes/components/shared/DateTime.cjsx +8 -6
  9. data/client/lanes/components/shared/FieldMixin.cjsx +3 -3
  10. data/client/lanes/components/shared/Icon.cjsx +1 -1
  11. data/client/lanes/components/shared/ImageAsset.cjsx +23 -11
  12. data/client/lanes/components/shared/NetworkActivityOverlay.cjsx +2 -0
  13. data/client/lanes/extension/Base.coffee +2 -0
  14. data/client/lanes/fonts/fontawesome-webfont.woff +0 -0
  15. data/client/lanes/fonts/fontawesome-webfont.woff2 +0 -0
  16. data/client/lanes/lib/RequestAssets.coffee +30 -0
  17. data/client/lanes/lib/all.js +1 -0
  18. data/client/lanes/lib/loader.js +93 -0
  19. data/client/lanes/lib/utilFunctions.coffee +12 -0
  20. data/client/lanes/models/Asset.coffee +3 -4
  21. data/client/lanes/models/AssociationMap.coffee +17 -6
  22. data/client/lanes/models/Base.coffee +20 -13
  23. data/client/lanes/models/Collection.coffee +4 -1
  24. data/client/lanes/models/PubSub.coffee +2 -3
  25. data/client/lanes/models/SmtpSettings.coffee +7 -0
  26. data/client/lanes/models/Sync.coffee +2 -2
  27. data/client/lanes/react/Viewport.coffee +14 -10
  28. data/client/lanes/react/mixins/FieldErrors.coffee +3 -4
  29. data/client/lanes/react/mixins/ReadEditingState.coffee +1 -0
  30. data/client/lanes/remote/Bootstrap.coffee +85 -0
  31. data/client/lanes/remote/api.coffee +2 -1
  32. data/client/lanes/remote/onDocumentReady.coffee +12 -0
  33. data/client/lanes/screens/Definitions.coffee +29 -12
  34. data/client/lanes/screens/SystemSettings.cjsx +12 -3
  35. data/client/lanes/styles/fonts/_bordered-pulled.scss +9 -0
  36. data/client/lanes/styles/fonts/_core.scss +1 -2
  37. data/client/lanes/styles/fonts/_icons.scss +56 -0
  38. data/client/lanes/styles/fonts/_mixins.scss +37 -4
  39. data/client/lanes/styles/fonts/_path.scss +2 -2
  40. data/client/lanes/styles/fonts/_screen-reader.scss +5 -0
  41. data/client/lanes/styles/fonts/_variables.scss +58 -2
  42. data/client/lanes/styles/fonts/font-awesome.scss +3 -1
  43. data/client/lanes/vendor/development/calendar.js +56 -57
  44. data/client/lanes/vendor/development/commons.js +31319 -29618
  45. data/client/lanes/vendor/development/data.js +8468 -7607
  46. data/client/lanes/vendor/development/helpers.js +265 -131
  47. data/client/lanes/vendor/development/toggle.js +288 -184
  48. data/client/lanes/vendor/development/ui.js +3387 -3492
  49. data/client/lanes/vendor/development/widgets.js +972 -1229
  50. data/client/lanes/vendor/production/calendar.js +60 -61
  51. data/client/lanes/vendor/production/commons.js +30695 -29032
  52. data/client/lanes/vendor/production/data.js +8457 -7598
  53. data/client/lanes/vendor/production/toggle.js +288 -184
  54. data/client/lanes/vendor/production/ui.js +3264 -3373
  55. data/client/lanes/vendor/production/widgets.js +972 -1229
  56. data/client/lanes/vendor/standalone/index.js +21106 -18761
  57. data/client/lanes/vendor/styles/toggle.scss +4 -3
  58. data/client/lanes/workspace/ScreenView.cjsx +2 -2
  59. data/client/lanes/workspace/styles/header.scss +4 -0
  60. data/config/routes.rb +0 -2
  61. data/db/migrate/01_create_system_settings.rb +1 -1
  62. data/db/migrate/02_create_assets.rb +1 -1
  63. data/lanes.gemspec +1 -0
  64. data/lib/lanes.rb +1 -0
  65. data/lib/lanes/access/track_modifications.rb +4 -2
  66. data/lib/lanes/api.rb +1 -0
  67. data/lib/lanes/api/cable.rb +11 -3
  68. data/lib/lanes/api/controller_base.rb +23 -19
  69. data/lib/lanes/api/default_routes.rb +9 -1
  70. data/lib/lanes/api/generic_controller.rb +1 -1
  71. data/lib/lanes/api/handlers/asset.rb +2 -3
  72. data/lib/lanes/api/helper_methods.rb +5 -11
  73. data/lib/lanes/api/pub_sub.rb +13 -7
  74. data/lib/lanes/api/request_wrapper.rb +1 -1
  75. data/lib/lanes/api/routing.rb +10 -7
  76. data/lib/lanes/api/to_json.rb +7 -0
  77. data/lib/lanes/asset.rb +4 -1
  78. data/lib/lanes/concerns/set_attribute_data.rb +2 -1
  79. data/lib/lanes/extension.rb +3 -1
  80. data/lib/lanes/mailer.rb +40 -0
  81. data/lib/lanes/rake_tasks.rb +4 -0
  82. data/lib/lanes/spec_helper.rb +11 -3
  83. data/lib/lanes/system_settings.rb +22 -9
  84. data/lib/lanes/version.rb +1 -1
  85. data/lib/lanes/workspace/extension.rb +5 -0
  86. data/npm-build/package.json +2 -2
  87. data/npm-build/react-toggle.js +1 -1
  88. data/npm-build/standalone.js +3 -0
  89. data/spec/command-reference-files/initial/Gemfile +1 -1
  90. data/spec/command-reference-files/initial/client/appy-app/Extension.coffee +2 -1
  91. data/spec/command-reference-files/model/db/migrate/20150218032025_create_test_tests.rb +1 -1
  92. data/spec/command-reference-files/screen/client/appy-app/Extension.coffee +2 -1
  93. data/spec/fixtures/system_settings.yml +8 -1
  94. data/spec/server/mailer_spec.rb +33 -0
  95. data/spec/server/system_settings_spec.rb +16 -0
  96. data/templates/client/Extension.coffee +2 -1
  97. data/templates/config/database.yml +1 -1
  98. data/templates/db/create_table_migration.rb +1 -1
  99. metadata +27 -6
  100. data/client/fonts/fontawesome-webfont.woff +0 -0
  101. data/client/fonts/fontawesome-webfont.woff2 +0 -0
  102. data/client/lanes/lib/loader.coffee +0 -100
  103. data/client/lanes/workspace/Modal.cjsx +0 -47
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 61899d6310319e01eeb5f8d3143de6381d59ef22
4
- data.tar.gz: 7684de7e8724e81d9bb3a294dc995d3f74a7a8e5
3
+ metadata.gz: 16b8badf6014b9cc559daad0046bffa56d08e791
4
+ data.tar.gz: b0018988b0ef191d183965f06ace441c7875b073
5
5
  SHA512:
6
- metadata.gz: 6037b22dcff009ca206df7145b6058bd8b0e4403e0459f1ce0367afc63a94db7cdd700d225d9cd1c29d86e065392bb087927e71b0f9d039a5c023a14d52b031e
7
- data.tar.gz: b227ee2a57df19679fff4767d23734ff4fff44cb92d98494ec1f75c97669793356a6b4610470de0885dba064d91a455ec93e8b0eeac092493ebe50331f67779c
6
+ metadata.gz: ddbc32e5e1dd43e8ca84e27e2a1bd02117dab786ab085900288990de9e32c7bfa406ffb23b3c32c7cb48a8c6da1c404f71f49b7064372b23bdfe922591de83a3
7
+ data.tar.gz: 2e4d091cfa1abcf667cf59dde4384f88c885825f436b7dd746528d9d5316f00ec3427db1cbb02176230bf9458d164d0dcaada35e1042ecf790dad3f83ba16a0c
@@ -7,17 +7,20 @@ class SystemSettings extends Lanes.Models.Base
7
7
  settings: "object"
8
8
 
9
9
  associations:
10
- logo: { model: "Lanes.Models.Asset" }
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
- api_host: { type: 'string', default: window.location.host }
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
- initial_workspace_screen_id: { type: 'string', setOnce: true }
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
- Lanes.config = new Config
72
+ configInstance = new Config
73
+
74
+ Object.defineProperty Lanes, 'config',
75
+ get: -> configInstance
76
+ set: -> throw new Error("Unable to reset config")
@@ -25,7 +25,7 @@ class Lanes.Access.Screens.UserManagement extends Lanes.React.Screen
25
25
  getSelection={@rolesForUser}
26
26
  setSelection={@setRolesForUser}
27
27
  choices={Lanes.Models.Role.all.models}
28
- fetchWhenOpen={false}
28
+ fetchOnSelect={false}
29
29
  name="role_names"
30
30
  />
31
31
 
@@ -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.value ||= ''
20
- <input type="text" {...props}
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 {...props} />
27
+ <LC.NumberInput unstyled {...@cleanProps(props)} />
24
28
  date: (props) ->
25
- <LC.DateTime {...props} inputOnly step={15}
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
- onClick={_.partial(@onButton, _, button)}>{button.title}</BS.Button>
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
- <BS.FormControl
69
- {...props} {...handlers}
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
- {_.moment(@model[@props.name]).format(@props.format)}
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: @fieldMixinGetValue()
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 props else _.omit(props, 'className')
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
- bindEvents: ->
15
- model: "change:#{@props.name} change:#{@props.name}_data"
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
- <form>
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>
@@ -1,3 +1,5 @@
1
+ ##= require 'lanes/components/shared/Icon'
2
+
1
3
  class Lanes.Components.NetworkActivityOverlay extends Lanes.React.Component
2
4
 
3
5
  propTypes:
@@ -6,6 +6,8 @@ class BaseExtension
6
6
  title: ->
7
7
  _.titleize @identifier
8
8
 
9
+ setBootstrapData: (data) ->
10
+ @data = data
9
11
 
10
12
  Lanes.Extensions.Base = Lanes.lib.MakeBaseClass(
11
13
  Lanes.Vendor.Ampersand.State, BaseExtension
@@ -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
+ )
@@ -3,6 +3,7 @@
3
3
  //= require ./objToParam
4
4
  //= require ./ModuleSupport
5
5
  //= require ./loader
6
+ //= require ./RequestAssets
6
7
  //= require ./MakeBaseClass
7
8
  //= require ./el
8
9
  //= require ./polyfills
@@ -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 ));