lanes 0.1.7 → 0.1.8
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/client/lanes/access/LoginDialog.coffee +0 -1
- data/client/lanes/access/screens/user-management/UserManagement.coffee +0 -1
- data/client/lanes/components/grid/Grid.coffee +7 -2
- data/client/lanes/components/radio-group/RadioGroup.coffee +0 -1
- data/client/lanes/components/record-finder/Clause.coffee +0 -1
- data/client/lanes/components/record-finder/Dialog.coffee +2 -2
- data/client/lanes/components/record-finder/RecordFinder.coffee +3 -2
- data/client/lanes/components/select2/Select2.coffee +8 -0
- data/client/lanes/components/select2/index.js +2 -0
- data/client/lanes/extension/Extensions.coffee +1 -1
- data/client/lanes/lib/ModuleSupport.coffee +1 -1
- data/client/lanes/models/ChangeSet.coffee +0 -1
- data/client/lanes/models/ModelAssociations.coffee +10 -10
- data/client/lanes/models/mixins/HasCodeField.coffee +3 -3
- data/client/lanes/screens/Definitions.coffee +0 -6
- data/client/lanes/views/ModelUpdate.coffee +0 -1
- data/client/lanes/workspace/ActiveScreensSwitcher.coffee +0 -1
- data/client/lanes/workspace/Layout.coffee +0 -1
- data/client/lanes/workspace/Navbar.coffee +0 -1
- data/client/lanes/workspace/Pages.coffee +0 -1
- data/client/lanes/workspace/ScreensMenu.coffee +0 -3
- data/lib/lanes/access/authentication_provider.rb +7 -7
- data/lib/lanes/api/coffeescript_processor.rb +64 -0
- data/lib/lanes/api/javascript_processor.rb +49 -41
- data/lib/lanes/api/root.rb +3 -1
- data/lib/lanes/concerns/pub_sub.rb +38 -40
- data/lib/lanes/configuration.rb +15 -9
- data/lib/lanes/version.rb +1 -1
- data/spec/command-reference-files/initial/Gemfile +1 -1
- data/spec/command-reference-files/initial/client/appy-app/Extension.coffee +0 -1
- data/spec/command-reference-files/model/client/appy-app/models/TestTest.coffee +0 -1
- data/spec/command-reference-files/screen/client/appy-app/screens/ready-set-go/ReadySetGo.coffee +0 -1
- data/spec/command-reference-files/screen/config/screens.rb +1 -0
- data/spec/command-reference-files/view/client/appy-app/views/BigView.coffee +0 -1
- data/spec/{api/javascript_processor_spec.rb → server/api/coffeescript_processor_spec.rb} +8 -2
- data/spec/server/concerns/pub_sub_spec.rb +55 -56
- data/templates/client/Extension.coffee +0 -1
- data/templates/client/models/Model.coffee +0 -1
- data/templates/client/screens/Screen.coffee +0 -1
- data/templates/client/views/View.coffee +0 -1
- data/templates/config/screen.rb +1 -0
- metadata +6 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b111e3e03f3c6f6a3bfffca0d087590b1ea0277a
|
4
|
+
data.tar.gz: ac11d9b1700311f927f06d06bcbee08de31c56e2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3fd3233d6311c8df5041a5a39e2245f5e5099fbddde5126c8b4202e51bb79e51a25391bec8a18f9c51d13d3d34f66e7e22e5ce54a0fc88e42ea9e568bfe473ce
|
7
|
+
data.tar.gz: bd91444bafa49fc750fb6750071903a4856bff5ececf54c577935b55382788798f5b574f57b91fd41f56fb80bb5dece54b208fbc981e8b23f69d3519e0ce7d48
|
@@ -8,7 +8,6 @@ _.extend( Lanes.$.fn.dataTableExt.oStdClasses,{
|
|
8
8
|
|
9
9
|
|
10
10
|
class Lanes.Components.Grid extends Lanes.Components.Base
|
11
|
-
FILE: FILE
|
12
11
|
|
13
12
|
domEvents:
|
14
13
|
'click button.refresh': 'reload'
|
@@ -48,6 +47,7 @@ class Lanes.Components.Grid extends Lanes.Components.Base
|
|
48
47
|
selectionMode: ['string', true, 'single']
|
49
48
|
editorConfig: { type: 'object' }
|
50
49
|
editingController: 'any' # either string or constructor fn
|
50
|
+
columnWidths: { type: 'array', default: -> [] }
|
51
51
|
|
52
52
|
initialize: ->
|
53
53
|
if this.viewport
|
@@ -191,7 +191,12 @@ class Lanes.Components.Grid extends Lanes.Components.Base
|
|
191
191
|
align = switch query_field.type
|
192
192
|
when 'integer','bigdec' then 'r'
|
193
193
|
else 'l'
|
194
|
-
|
194
|
+
options = {
|
195
|
+
id: query_field.id, title: query_field.title,
|
196
|
+
className: align, "targets": [ index ]
|
197
|
+
}
|
198
|
+
options['width'] = @columnWidths[index] if @columnWidths[index]
|
199
|
+
options
|
195
200
|
|
196
201
|
_dataFromModel: (model)->
|
197
202
|
data = []
|
@@ -1,5 +1,4 @@
|
|
1
1
|
class Lanes.Components.RecordFinder.Dialog extends Lanes.Components.ModalDialog
|
2
|
-
FILE: FILE
|
3
2
|
|
4
3
|
domEvents:
|
5
4
|
'click .add-clause': 'addClause'
|
@@ -12,7 +11,7 @@ class Lanes.Components.RecordFinder.Dialog extends Lanes.Components.ModalDialog
|
|
12
11
|
hook: 'grid'
|
13
12
|
component: 'Grid'
|
14
13
|
options: ->
|
15
|
-
{ recordQuery: @recordQuery }
|
14
|
+
_.extend(@gridOptions||{}, { recordQuery: @recordQuery, options: @gridOptions })
|
16
15
|
query_clauses:
|
17
16
|
container: '.query-clauses'
|
18
17
|
view: Lanes.Components.RecordFinder.Clause, collection: 'clauses'
|
@@ -22,6 +21,7 @@ class Lanes.Components.RecordFinder.Dialog extends Lanes.Components.ModalDialog
|
|
22
21
|
|
23
22
|
session:
|
24
23
|
recordQuery: 'model'
|
24
|
+
gridOptions: 'object'
|
25
25
|
clauses: 'collection'
|
26
26
|
|
27
27
|
initialize:(options)->
|
@@ -1,5 +1,4 @@
|
|
1
1
|
class Lanes.Components.RecordFinder extends Lanes.Components.Base
|
2
|
-
FILE: FILE
|
3
2
|
|
4
3
|
writeTemplateName: 'field'
|
5
4
|
writeTemplateData: ->
|
@@ -13,6 +12,7 @@ class Lanes.Components.RecordFinder extends Lanes.Components.Base
|
|
13
12
|
withAssociations: 'array'
|
14
13
|
invalid_chars: 'regex'
|
15
14
|
recordQuery: 'model'
|
15
|
+
gridOptions: 'gridOptions'
|
16
16
|
fieldName: 'string'
|
17
17
|
queryField: [ 'string', false, 'code' ]
|
18
18
|
|
@@ -30,7 +30,8 @@ class Lanes.Components.RecordFinder extends Lanes.Components.Base
|
|
30
30
|
|
31
31
|
displayFinder: ->
|
32
32
|
finder = new Lanes.Components.RecordFinder.Dialog(
|
33
|
-
|
33
|
+
gridOptions: @gridOptions, parent:this
|
34
|
+
title: @title, recordQuery: @recordQuery
|
34
35
|
)
|
35
36
|
finder.show().then( (dlg)->
|
36
37
|
dlg.remove().record
|
@@ -0,0 +1,8 @@
|
|
1
|
+
class Lanes.Components.Select2 extends Lanes.Components.Base
|
2
|
+
|
3
|
+
writeTemplate: ->
|
4
|
+
multiple = if this.multiple then "multiple" else ""
|
5
|
+
"<div><select class='form-control' #{multiple} name='#{this.field_name}' data-hook='choices-input'></select></div>"
|
6
|
+
|
7
|
+
readTemplate: ->
|
8
|
+
"<div class='ro-input' name='#{this.field_name}'></div>"
|
@@ -18,7 +18,7 @@ Lanes.Extensions = {
|
|
18
18
|
|
19
19
|
makeNamespace: (identifier)->
|
20
20
|
for ns in ['Models','Views','Controllers','Screens','Components']
|
21
|
-
Lanes.namespace("#{identifier}.#{ns}")
|
21
|
+
Lanes.namespace("#{identifier}.#{ns}.Mixins")
|
22
22
|
|
23
23
|
controlling: ->
|
24
24
|
this.get( @controlling_id )
|
@@ -15,7 +15,7 @@ class Lanes.Models.AssocationMap
|
|
15
15
|
getClassFor: (name)->
|
16
16
|
definition = @definitions[name]
|
17
17
|
object = definition.model || definition.collection
|
18
|
-
Lanes.u.findObject(
|
18
|
+
Lanes.u.findObject(object, 'Models', @klass::FILE)
|
19
19
|
|
20
20
|
getOptions: (name, definition, model)->
|
21
21
|
options = { parent: model }
|
@@ -24,32 +24,32 @@ class Lanes.Models.AssocationMap
|
|
24
24
|
options
|
25
25
|
|
26
26
|
# will be called in the scope of the model
|
27
|
-
createModel: (association, name, definition, fk, pk,
|
28
|
-
|
27
|
+
createModel: (association, name, definition, fk, pk, target_class)->
|
28
|
+
target_class ||= association.getClassFor(name)
|
29
29
|
options = association.getOptions(name,definition,this)
|
30
30
|
model_id = this.get(pk)
|
31
31
|
if model_id && model_id == this._cache[name]?.id
|
32
32
|
this._cache[name]
|
33
33
|
else
|
34
|
-
|
34
|
+
target_class.findOrCreate(options)
|
35
35
|
|
36
36
|
# will be called in the scope of the model
|
37
|
-
createCollection: (association, name, definition, fk, pk,
|
38
|
-
|
37
|
+
createCollection: (association, name, definition, fk, pk, target_class)->
|
38
|
+
target_class ||= association.getClassFor(name)
|
39
39
|
options = association.getOptions(name,definition,this)
|
40
40
|
options.filter ||= {}
|
41
41
|
options.filter[fk]=this.get(pk)
|
42
42
|
|
43
|
-
if
|
44
|
-
new
|
43
|
+
if target_class::isCollection
|
44
|
+
new target_class(options.models||[],options)
|
45
45
|
else
|
46
|
-
options.model=
|
46
|
+
options.model=target_class
|
47
47
|
new Lanes.Models.AssociationCollection(options.models||[],options)
|
48
48
|
# returns the definition for the derived property
|
49
49
|
derivedDefinition: (name,definition)->
|
50
50
|
createFn = _.partial(
|
51
51
|
if definition.model then this.createModel else this.createCollection,
|
52
|
-
this, name, definition, this.fk(name), this.pk(name)
|
52
|
+
this, name, definition, this.fk(name), this.pk(name)
|
53
53
|
)
|
54
54
|
{ deps: [this.pk(name)], fn: createFn }
|
55
55
|
|
@@ -2,11 +2,11 @@ Lanes.Models.Mixins.HasCodeField = {
|
|
2
2
|
|
3
3
|
INVALID: /[^A-Z0-9a-z]/
|
4
4
|
|
5
|
-
included: ->
|
6
|
-
|
5
|
+
included: (klass)->
|
6
|
+
klass::INVALID_CODE_CHARS ||= Lanes.Models.mixins.Lanes.sCodeField.INVALID
|
7
7
|
|
8
8
|
initialize: ->
|
9
|
-
this.on('change:code', this.upcaseCode
|
9
|
+
this.on('change:code', this.upcaseCode)
|
10
10
|
|
11
11
|
upcaseCode: ->
|
12
12
|
this.set('code', this.get('code').toUpperCase())
|
@@ -1,5 +1,4 @@
|
|
1
1
|
class ScreenView extends Lanes.Models.BasicModel
|
2
|
-
FILE: FILE
|
3
2
|
|
4
3
|
session:
|
5
4
|
screen: 'object'
|
@@ -31,7 +30,6 @@ class ScreenView extends Lanes.Models.BasicModel
|
|
31
30
|
|
32
31
|
|
33
32
|
class ScreenDefinition extends Lanes.Models.BasicModel
|
34
|
-
FILE: FILE
|
35
33
|
|
36
34
|
session:
|
37
35
|
id: 'string'
|
@@ -86,7 +84,6 @@ class ScreenDefinition extends Lanes.Models.BasicModel
|
|
86
84
|
|
87
85
|
|
88
86
|
class ScreenViewSet extends Lanes.Models.BasicCollection
|
89
|
-
FILE: FILE
|
90
87
|
|
91
88
|
model: ScreenView
|
92
89
|
|
@@ -125,7 +122,6 @@ class ScreenViewSet extends Lanes.Models.BasicCollection
|
|
125
122
|
|
126
123
|
|
127
124
|
class ScreenSet extends Lanes.Models.BasicCollection
|
128
|
-
FILE: FILE
|
129
125
|
|
130
126
|
model: ScreenDefinition
|
131
127
|
|
@@ -138,7 +134,6 @@ class ScreenSet extends Lanes.Models.BasicCollection
|
|
138
134
|
|
139
135
|
|
140
136
|
class MenuGroup extends Lanes.Models.BasicModel
|
141
|
-
FILE: FILE
|
142
137
|
|
143
138
|
session:
|
144
139
|
id: 'string'
|
@@ -156,7 +151,6 @@ class MenuGroup extends Lanes.Models.BasicModel
|
|
156
151
|
})
|
157
152
|
|
158
153
|
class MenuGroupSet extends Lanes.Models.BasicCollection
|
159
|
-
FILE: FILE
|
160
154
|
|
161
155
|
constructor: -> super
|
162
156
|
model: MenuGroup
|
@@ -1,7 +1,6 @@
|
|
1
1
|
class ScreenList extends Lanes.Views.Base
|
2
2
|
|
3
3
|
template: "<li><a href='#'><span></span><i></i></a></li>"
|
4
|
-
FILE: FILE
|
5
4
|
mixins:[
|
6
5
|
Lanes.Workspace.WorkspaceView
|
7
6
|
]
|
@@ -19,7 +18,6 @@ class ScreenList extends Lanes.Views.Base
|
|
19
18
|
class ScreenGroup extends Lanes.Views.Base
|
20
19
|
|
21
20
|
template: '<li class="group"><a class="heading" href="#"><span></span><i></i></a><ul></ul></li>'
|
22
|
-
FILE: FILE
|
23
21
|
mixins:[
|
24
22
|
Lanes.Workspace.WorkspaceView
|
25
23
|
]
|
@@ -47,7 +45,6 @@ class ScreenGroup extends Lanes.Views.Base
|
|
47
45
|
|
48
46
|
class Lanes.Workspace.ScreensMenu extends Lanes.Views.Base
|
49
47
|
|
50
|
-
FILE: FILE
|
51
48
|
templateName: 'screens-menu'
|
52
49
|
mixins:[
|
53
50
|
Lanes.Workspace.WorkspaceView
|
@@ -10,10 +10,10 @@ module Lanes
|
|
10
10
|
|
11
11
|
def current_user
|
12
12
|
@current_user ||= (
|
13
|
-
if Lanes.env.test? && request.env['HTTP_X_TESTING_USER']
|
13
|
+
if Lanes.env.test? && request.env['HTTP_X_TESTING_USER'].present?
|
14
14
|
Lanes::User.where(login: request.env['HTTP_X_TESTING_USER']).first
|
15
15
|
else
|
16
|
-
Lanes::User.where(id:
|
16
|
+
Lanes::User.where(id: request.session['user_id']).first
|
17
17
|
end
|
18
18
|
)
|
19
19
|
end
|
@@ -23,7 +23,7 @@ module Lanes
|
|
23
23
|
end
|
24
24
|
|
25
25
|
def error_message_for_access
|
26
|
-
return "Unable to " + case
|
26
|
+
return "Unable to " + case request.request_method
|
27
27
|
when 'GET' then "read"
|
28
28
|
when 'POST','PATCH','PUT' then "write"
|
29
29
|
when 'DELETE' then "delete"
|
@@ -34,13 +34,13 @@ module Lanes
|
|
34
34
|
|
35
35
|
def allowed_access_to?(klass)
|
36
36
|
return false if current_user.nil?
|
37
|
-
case
|
37
|
+
case request.request_method
|
38
38
|
when 'GET'
|
39
|
-
klass.can_read_attributes?(
|
39
|
+
klass.can_read_attributes?(request.params,current_user)
|
40
40
|
when 'POST','PATCH','PUT'
|
41
|
-
klass.can_write_attributes?(
|
41
|
+
klass.can_write_attributes?(request.params,current_user)
|
42
42
|
when 'DELETE'
|
43
|
-
klass.can_delete_attributes?(
|
43
|
+
klass.can_delete_attributes?(request.params,current_user)
|
44
44
|
else
|
45
45
|
false
|
46
46
|
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# Coffeescript has two shortcomings with regards to Lanes
|
2
|
+
#
|
3
|
+
# The first is that it's extends format is incompatible with AmpersandState,
|
4
|
+
# State does quite a bit more via it's own .extend methods.
|
5
|
+
# Accordingly, we substitute our own "extend" call whenever we encounter a coffeescript extends
|
6
|
+
#
|
7
|
+
# The second issue is that if a constructor isn't present, coffeescript with generate it's own
|
8
|
+
# blank implementation that fails to call "super". We add a constructor that does call super if one's missing.
|
9
|
+
|
10
|
+
module Lanes
|
11
|
+
module API
|
12
|
+
class CoffeeScriptProcessor < JsAssetCompiler
|
13
|
+
|
14
|
+
class CoffeeClass
|
15
|
+
attr_reader :name, :extends, :contents, :file_contents, :indent
|
16
|
+
def initialize(name, extends, file_contents)
|
17
|
+
@name=name; @extends=extends; @file_contents=file_contents
|
18
|
+
file_contents.gsub!(/class\s+#{name}\s+.*?\n/,"class #{name}\n")
|
19
|
+
@contents = @file_contents[/(class #{name}\n.*?)(\n\w|\Z)/m,1]
|
20
|
+
@indent = @contents[/\n(\s+)(\w+):/,1] || ' '
|
21
|
+
end
|
22
|
+
|
23
|
+
def ensure_property(property_name, definition)
|
24
|
+
if contents !~ /^\s+#{property_name}\s*:/
|
25
|
+
# figure out how much to indent, sigh.
|
26
|
+
file_contents.gsub!(/class #{name}\n/,
|
27
|
+
"\\0#{indent}#{property_name}: #{definition}\n")
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def save
|
32
|
+
file_contents.gsub!( /(class #{name}\n.*?)(\n\w|\Z)/m,
|
33
|
+
"\\1\n#{extends}.extend(#{name})\n\\2" )
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
self.registered_extension = '.coffee'
|
38
|
+
|
39
|
+
attr_reader :contents
|
40
|
+
|
41
|
+
CONSTRUCTOR = /constructor\s*:/
|
42
|
+
|
43
|
+
EXTENDING_CLASS_DEFINITION = /class\s+([\w|\.]+)\s+extends\s+([\w|\.]+)\s*?\n/
|
44
|
+
|
45
|
+
def cleaned
|
46
|
+
@contents = data.dup
|
47
|
+
data.scan(EXTENDING_CLASS_DEFINITION) do |match|
|
48
|
+
(name, extends) = match
|
49
|
+
cc = CoffeeClass.new(name, extends, contents)
|
50
|
+
cc.ensure_property("constructor", "-> super")
|
51
|
+
cc.ensure_property("FILE", "FILE")
|
52
|
+
cc.save
|
53
|
+
end
|
54
|
+
contents
|
55
|
+
end
|
56
|
+
|
57
|
+
def evaluate(scope, locals, &block)
|
58
|
+
wrap_js scope, ::CoffeeScript.compile(cleaned, bare: true)
|
59
|
+
end
|
60
|
+
|
61
|
+
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -40,47 +40,53 @@ module Lanes
|
|
40
40
|
|
41
41
|
end
|
42
42
|
|
43
|
-
class CoffeeScriptWrapper < JsAssetCompiler
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
end
|
43
|
+
# class CoffeeScriptWrapper < JsAssetCompiler
|
44
|
+
# self.registered_extension = '.coffee'
|
45
|
+
|
46
|
+
# CONSTRUCTOR = /constructor\s*:/
|
47
|
+
# CLASS_DEFINITION = /\s*class\s+([\w|\.]+)/
|
48
|
+
# EXTENDING_CLASS = /class\s+([\w|\.]+)\s+extends\s+([\w|\.]+)\s*?\n/
|
49
|
+
|
50
|
+
# # Coffeescript has two shortcomings with regards to Lanes
|
51
|
+
# #
|
52
|
+
# # The first is that it's extends format is incompatible with AmpersandState,
|
53
|
+
# # State does quite a bit more via it's own .extend methods.
|
54
|
+
# # Accordingly, we substitute our own "extend" call whenever we encounter a coffeescript extends
|
55
|
+
# #
|
56
|
+
# # The second issue is that if a constructor isn't present, coffeescript with generate it's own
|
57
|
+
# # blank implementation that fails to call "super". We add a constructor that does call super if one's missing.
|
58
|
+
|
59
|
+
# def cleaned
|
60
|
+
# contents = data.dup
|
61
|
+
# data.scan(CLASS_DEFINITION) do |match|
|
62
|
+
# (name, extends) = match
|
63
|
+
# definition = get_definition(name)
|
64
|
+
|
65
|
+
|
66
|
+
# # is it missing a constructor?
|
67
|
+
# if definition !~ /constructor:/
|
68
|
+
# # figure out how much to indent, sigh.
|
69
|
+
# indent = definition[/\n(\s+)(\w+):/,1] || ' '
|
70
|
+
# contents.gsub!(/class #{name}\n/,"\\0#{indent}constructor: -> super\n")
|
71
|
+
|
72
|
+
# end
|
73
|
+
# contents.gsub!( /(class #{name}\n.*?)(\n\w|\Z)/m, "\\1\n#{extends}.extend(#{name})\n\\2" )
|
74
|
+
|
75
|
+
# contents
|
76
|
+
# #contents << "#{extends}.extend(#{name})\n"
|
77
|
+
# end
|
78
|
+
# contents
|
79
|
+
# end
|
80
|
+
|
81
|
+
# def evaluate(scope, locals, &block)
|
82
|
+
# wrap_js scope, ::CoffeeScript.compile(cleaned, bare: true)
|
83
|
+
# end
|
84
|
+
|
85
|
+
# def get_definition(name)
|
86
|
+
# contents.gsub!(/class\s+#{name}\s+.*?\n/,"class #{name}\n")
|
87
|
+
# definition = contents[/(class #{name}\n.*?)(\n\w|\Z)/m,1]
|
88
|
+
# end
|
89
|
+
# end
|
84
90
|
|
85
91
|
class Es6Compiler < JsAssetCompiler
|
86
92
|
self.registered_extension = '.es6'
|
@@ -129,3 +135,5 @@ module Lanes
|
|
129
135
|
|
130
136
|
end
|
131
137
|
end
|
138
|
+
|
139
|
+
require_relative 'coffeescript_processor'
|
data/lib/lanes/api/root.rb
CHANGED
@@ -35,7 +35,9 @@ module Lanes
|
|
35
35
|
PubSub.initialize(self)
|
36
36
|
Extensions.load_controlling_config
|
37
37
|
# late load in case an extension has provided an alternative implementation
|
38
|
-
|
38
|
+
unless API.const_defined?(:AuthenticationProvider)
|
39
|
+
require "lanes/api/null_authentication_provider"
|
40
|
+
end
|
39
41
|
# use Rack::Csrf, :skip=>['GET:/'], :raise => true
|
40
42
|
end
|
41
43
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
module Lanes::Concerns
|
2
2
|
|
3
|
-
# Event subscription and publishing for
|
3
|
+
# Event subscription and publishing for Models
|
4
4
|
# Every model has certain built-in events (:save, :create, :update, :destroy)
|
5
5
|
# And may also implement custom events that reflect the models domain
|
6
6
|
# @example Send an email when a customer's name is updated
|
@@ -50,31 +50,37 @@ module Lanes::Concerns
|
|
50
50
|
class_attribute :_event_listeners
|
51
51
|
base.valid_event_names = [ :save, :create, :update, :destroy ]
|
52
52
|
|
53
|
-
base.after_save :
|
54
|
-
base.after_create :
|
55
|
-
base.after_update :
|
56
|
-
base.after_destroy :
|
53
|
+
base.after_save :fire_after_save_pubsub_events
|
54
|
+
base.after_create :fire_after_create_pubsub_events
|
55
|
+
base.after_update :fire_after_update_pubsub_events
|
56
|
+
base.after_destroy :fire_after_destroy_pubsub_events
|
57
57
|
end
|
58
58
|
|
59
59
|
module ClassMethods
|
60
60
|
def inherited(base)
|
61
61
|
super
|
62
62
|
klass = base.to_s.demodulize
|
63
|
-
|
64
|
-
#p klass
|
65
|
-
# if klass=="Tester"
|
66
|
-
# binding.pry
|
67
|
-
# end
|
68
63
|
events = PubSub::PendingListeners.claim( klass )
|
69
|
-
events.each{ | name, procs |
|
70
|
-
|
64
|
+
events.each{ | name, procs |
|
65
|
+
procs.each{|pr|
|
66
|
+
base.send(:_add_event_listener, name, &pr)
|
67
|
+
}
|
68
|
+
}
|
71
69
|
end
|
72
70
|
|
73
71
|
def observe( event, &block )
|
74
|
-
|
72
|
+
unless self.valid_event_names.include?(event.to_sym)
|
73
|
+
raise InvalidEvent.new("#{event} is not a valid event for #{self}")
|
74
|
+
end
|
75
75
|
_add_event_listener( event.to_sym, &block )
|
76
76
|
end
|
77
77
|
|
78
|
+
protected
|
79
|
+
|
80
|
+
def has_additional_events( *names )
|
81
|
+
self.valid_event_names += names.map{ |name| name.to_sym }
|
82
|
+
end
|
83
|
+
|
78
84
|
private
|
79
85
|
|
80
86
|
def _add_event_listener(name, &block)
|
@@ -84,46 +90,38 @@ module Lanes::Concerns
|
|
84
90
|
self._event_listeners = self._event_listeners.dup
|
85
91
|
self._event_listeners[name] = listeners
|
86
92
|
end
|
87
|
-
|
88
|
-
def _ensure_validate_event(event)
|
89
|
-
unless self.valid_event_names.include?(event.to_sym)
|
90
|
-
raise InvalidEvent.new("#{event} is not a valid event for #{self}")
|
91
|
-
end
|
92
|
-
end
|
93
|
-
|
94
|
-
def has_additional_events( *names )
|
95
|
-
self.valid_event_names += names.map{ |name| name.to_sym }
|
96
|
-
end
|
97
93
|
end
|
98
94
|
|
99
95
|
protected
|
100
96
|
|
101
|
-
def
|
102
|
-
|
97
|
+
def fire_after_destroy_pubsub_events
|
98
|
+
fire_pubsub_event(:update, self)
|
103
99
|
end
|
104
|
-
|
105
|
-
|
100
|
+
|
101
|
+
def fire_after_update_pubsub_events
|
102
|
+
fire_pubsub_event(:update, self)
|
106
103
|
end
|
107
|
-
|
108
|
-
|
104
|
+
|
105
|
+
def fire_after_create_pubsub_events
|
106
|
+
fire_pubsub_event(:create, self)
|
109
107
|
end
|
110
|
-
|
111
|
-
|
108
|
+
|
109
|
+
def fire_after_save_pubsub_events
|
110
|
+
fire_pubsub_event(:save, self)
|
112
111
|
end
|
113
112
|
|
114
|
-
def
|
115
|
-
self.class.
|
116
|
-
|
117
|
-
|
113
|
+
def fire_pubsub_event(name, *arguments)
|
114
|
+
return if self.class._event_listeners.nil? ||
|
115
|
+
!self.class._event_listeners.has_key?(name.to_sym)
|
116
|
+
arguments = arguments.dup.unshift(self)
|
117
|
+
self.class._event_listeners[ name.to_sym ].each{ | block |
|
118
|
+
block.call(*arguments)
|
119
|
+
}
|
118
120
|
end
|
119
121
|
|
120
122
|
private
|
121
123
|
|
122
|
-
def
|
123
|
-
return if self.class._event_listeners.nil? ||
|
124
|
-
!self.class._event_listeners.has_key?(name.to_sym)
|
125
|
-
|
126
|
-
self.class._event_listeners[ name.to_sym ].each{ | block | block.call(*arguments) }
|
124
|
+
def _fire_pubsub_event( name, *arguments )
|
127
125
|
end
|
128
126
|
end
|
129
127
|
|
data/lib/lanes/configuration.rb
CHANGED
@@ -51,25 +51,31 @@ module Lanes
|
|
51
51
|
# Database tables will have this prefix applied to them
|
52
52
|
config_option :table_prefix, ''
|
53
53
|
|
54
|
-
|
55
|
-
config_option :default_javascript_tag_options, {}
|
56
|
-
|
54
|
+
# The configuration environment to use, test, development, production
|
57
55
|
config_option :environment, (ENV['RACK_ENV'] || 'development').to_sym
|
56
|
+
|
58
57
|
# The secret key to use for session cookies.
|
59
58
|
config_option :session_secret_key_base, '1234', silent: true
|
59
|
+
|
60
|
+
# Configuration for Redis
|
60
61
|
config_option :redis, { path: "/tmp/redis.sock" }
|
61
|
-
config_option :pubsub_key, nil
|
62
|
-
config_option :pubsub_host, nil
|
63
|
-
config_option :pubsub_timeout, 10
|
64
62
|
|
65
|
-
|
66
|
-
config_option :es6_transpiler_options, '-t '
|
63
|
+
# Title of application
|
67
64
|
config_option :app_title, "Lanes Test"
|
65
|
+
|
66
|
+
# url prefix to use for assets
|
68
67
|
config_option :assets_path_prefix, "/assets"
|
68
|
+
|
69
|
+
# prefix to use for all urls
|
69
70
|
config_option :mounted_at, ''
|
71
|
+
|
72
|
+
# The initial view class to display
|
70
73
|
config_option :root_view, 'Lanes.Workspace.Layout'
|
74
|
+
|
75
|
+
# Screen to display on load (if workspace extension is used)
|
71
76
|
config_option :initial_workspace_screen_id, ''
|
72
|
-
|
77
|
+
|
78
|
+
# types of assets to include into compiled package
|
73
79
|
config_option :static_asset_types, ['images','fonts']
|
74
80
|
end
|
75
81
|
|
data/lib/lanes/version.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
require "lanes/spec_helper"
|
2
2
|
|
3
|
-
class
|
3
|
+
class CoffeeScriptProcessor < Lanes::TestCase
|
4
4
|
|
5
5
|
SCRIPT = <<-EOS
|
6
6
|
class NS.Baz
|
@@ -30,6 +30,7 @@ class NS.Baz
|
|
30
30
|
alert(msg);
|
31
31
|
|
32
32
|
class NS.Bar
|
33
|
+
FILE: FILE
|
33
34
|
constructor: -> super
|
34
35
|
squawk:->
|
35
36
|
this.alert("Hello World!")
|
@@ -37,6 +38,7 @@ class NS.Bar
|
|
37
38
|
NS.Baz.extend(NS.Bar)
|
38
39
|
|
39
40
|
class Foo
|
41
|
+
FILE: FILE
|
40
42
|
constructor: ->
|
41
43
|
this.called=true
|
42
44
|
super
|
@@ -65,6 +67,8 @@ NS.Baz = (function() {
|
|
65
67
|
})();
|
66
68
|
|
67
69
|
NS.Bar = (function() {
|
70
|
+
Bar.prototype.FILE = FILE;
|
71
|
+
|
68
72
|
function Bar() {
|
69
73
|
Bar.__super__.constructor.apply(this, arguments);
|
70
74
|
}
|
@@ -80,6 +84,8 @@ NS.Bar = (function() {
|
|
80
84
|
NS.Baz.extend(NS.Bar);
|
81
85
|
|
82
86
|
Foo = (function() {
|
87
|
+
Foo.prototype.FILE = FILE;
|
88
|
+
|
83
89
|
function Foo() {
|
84
90
|
this.called = true;
|
85
91
|
Foo.__super__.constructor.apply(this, arguments);
|
@@ -101,7 +107,7 @@ EOS
|
|
101
107
|
Scope = Struct.new(:logical_path)
|
102
108
|
|
103
109
|
def test_coffeescript_generation
|
104
|
-
template = API::
|
110
|
+
template = API::CoffeeScriptProcessor.new{ |t| SCRIPT }
|
105
111
|
assert_equal CLEANED, template.cleaned
|
106
112
|
|
107
113
|
|
@@ -5,123 +5,122 @@ describe "PubSub" do
|
|
5
5
|
include ActiveRecordMocks::IncludeMe
|
6
6
|
around do | test |
|
7
7
|
with_mocked_tables do |m|
|
8
|
-
|
9
|
-
|
10
|
-
t.belongs_to :evhm, class_name: "Evhm", listen: { create: 'on_create_hm' },
|
11
|
-
inverse_of: :evbt
|
12
|
-
t.layout do |l|
|
13
|
-
l.integer :evhm_id
|
14
|
-
end
|
15
|
-
t.parent_class "Lanes::Model"
|
16
|
-
end
|
17
|
-
class Evbt
|
8
|
+
|
9
|
+
class A < Lanes::Model
|
18
10
|
has_additional_events :test_one
|
19
|
-
def
|
20
|
-
|
11
|
+
def on_save_b(*args)
|
12
|
+
end
|
13
|
+
def on_save_event_tester(*args)
|
21
14
|
end
|
22
15
|
end
|
23
|
-
|
24
16
|
m.create_table do |t|
|
25
|
-
t.model_name :
|
17
|
+
t.model_name :A
|
26
18
|
t.parent_class "Lanes::Model"
|
27
|
-
t.belongs_to :
|
19
|
+
t.belongs_to :b_model, class_name: "B", listen: { save: :on_save_b },
|
20
|
+
inverse_of: :a_model
|
28
21
|
|
29
|
-
t.
|
22
|
+
t.belongs_to :event_tester, class_name: "EventTester", inverse_of: :a_models,
|
23
|
+
listen: { save: 'on_save_event_tester' }
|
30
24
|
|
31
25
|
t.layout do |l|
|
32
|
-
l.integer :
|
33
|
-
l.
|
26
|
+
l.integer :b_model_id, :b_id
|
27
|
+
l.integer :event_tester_id
|
34
28
|
end
|
35
29
|
end
|
36
30
|
|
31
|
+
class B < Lanes::Model
|
32
|
+
def on_save_a(*args)
|
33
|
+
end
|
34
|
+
end
|
37
35
|
table = m.create_table do |t|
|
38
|
-
t.model_name :
|
39
|
-
t.belongs_to :evbt, class_name: "Evbt", listen: { save: 'on_create_bt' },
|
40
|
-
inverse_of: :evhm
|
41
|
-
t.belongs_to :event_tester, class_name: "EventTester", inverse_of: :evhm,
|
42
|
-
listen: { save: 'on_save_event_tester' }
|
36
|
+
t.model_name :B
|
43
37
|
t.parent_class "Lanes::Model"
|
38
|
+
t.has_one :a_model, class_name: "A", listen: { save: 'on_save_a' },
|
39
|
+
inverse_of: :b_model
|
44
40
|
t.layout do | l |
|
45
41
|
l.string :mumble
|
46
|
-
l.integer :evbt_id, :event_tester_id
|
47
42
|
end
|
48
43
|
end
|
49
|
-
|
44
|
+
|
45
|
+
class EventTester < Lanes::Model
|
50
46
|
end
|
51
47
|
|
48
|
+
m.create_table do |t|
|
49
|
+
t.model_name :EventTester
|
50
|
+
t.parent_class "Lanes::Model"
|
51
|
+
t.has_many :a_models, class_name: 'A', inverse_of: :event_tester
|
52
52
|
|
53
|
+
t.layout do |l|
|
54
|
+
l.string :name, :number
|
55
|
+
end
|
56
|
+
end
|
53
57
|
|
54
58
|
test.call
|
59
|
+
|
55
60
|
end
|
56
61
|
end
|
57
62
|
|
58
63
|
it "listens to other associations" do
|
59
|
-
|
60
|
-
|
61
|
-
b
|
62
|
-
|
63
|
-
assert
|
64
|
+
a=A.new
|
65
|
+
b=a.build_b_model
|
66
|
+
assert b.a_model
|
67
|
+
a.expects(:on_save_b)
|
68
|
+
assert a.save
|
64
69
|
|
65
70
|
et = EventTester.new
|
66
|
-
|
67
|
-
|
68
|
-
|
71
|
+
a=et.a_models.build
|
72
|
+
a.expects(:on_save_event_tester)
|
73
|
+
et.save
|
69
74
|
end
|
70
75
|
|
71
76
|
it "registers" do
|
72
|
-
assert_equal [ :save, :create, :update, :destroy ],EventTester.valid_event_names
|
73
|
-
assert_equal [ :save, :create, :update, :destroy, :test_one ],
|
77
|
+
assert_equal [ :save, :create, :update, :destroy ], EventTester.valid_event_names
|
78
|
+
assert_equal [ :save, :create, :update, :destroy, :test_one ], A.valid_event_names
|
74
79
|
end
|
75
80
|
|
76
81
|
it "can only observe valid events" do
|
77
|
-
assert_raises(
|
82
|
+
assert_raises(EventTester::InvalidEvent) do
|
78
83
|
EventTester.observe(:invalid_event) do | ev |
|
79
84
|
end
|
80
85
|
end
|
81
|
-
assert_raises(
|
82
|
-
|
86
|
+
assert_raises(EventTester::InvalidEvent) do
|
87
|
+
B.observe(:test_two) do | ev |
|
83
88
|
end
|
84
|
-
EventTester.new.send(:fire_event,:invalid_event)
|
85
89
|
end
|
86
|
-
assert_raises(
|
87
|
-
|
88
|
-
end
|
89
|
-
end
|
90
|
-
assert_raises( EventTester::InvalidEvent) do
|
91
|
-
Evhm.observe(:test_one) do | ev |
|
90
|
+
assert_raises(EventTester::InvalidEvent) do
|
91
|
+
A.observe(:glub_glub) do | ev |
|
92
92
|
end
|
93
93
|
end
|
94
94
|
begin
|
95
|
-
|
95
|
+
B.observe(:test_one) do | ev |
|
96
96
|
end
|
97
97
|
rescue EventTester::InvalidEvent=>e
|
98
|
-
assert_equal 'test_one is not a valid event for
|
98
|
+
assert_equal 'test_one is not a valid event for B', e.to_s
|
99
99
|
end
|
100
100
|
end
|
101
101
|
|
102
102
|
it "events can be subscribed to" do
|
103
103
|
EventTester.observe(:save) do | ev |
|
104
|
-
|
105
104
|
end
|
106
105
|
end
|
107
106
|
|
108
107
|
it "can be fired and observed" do
|
109
108
|
results=[]
|
110
|
-
|
109
|
+
A.observe(:test_one) do | ev, one, two |
|
111
110
|
results = [ ev, one, two ]
|
112
111
|
end
|
113
|
-
|
114
|
-
|
115
|
-
assert_equal [
|
112
|
+
a=A.new
|
113
|
+
a.send(:fire_pubsub_event, :test_one, 3, 5 )
|
114
|
+
assert_equal [a, 3, 5], results
|
116
115
|
|
117
|
-
|
118
|
-
assert_equal [
|
116
|
+
a.send(:fire_pubsub_event, :test_one, 'foo' )
|
117
|
+
assert_equal [a, 'foo', nil], results
|
119
118
|
end
|
120
119
|
|
121
120
|
|
122
121
|
it "can use custom event assertions" do
|
123
|
-
assert_event_fires(
|
124
|
-
|
122
|
+
assert_event_fires(A, :test_one) do
|
123
|
+
A.new.send(:fire_pubsub_event, :test_one, 3, 5)
|
125
124
|
end
|
126
125
|
assert_equal [ 3, 5 ], last_event_results[1..-1]
|
127
126
|
end
|
data/templates/config/screen.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: lanes
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.8
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nathan Stitt
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-03-
|
11
|
+
date: 2015-03-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -527,6 +527,8 @@ files:
|
|
527
527
|
- client/lanes/components/select-field/SelectField.coffee
|
528
528
|
- client/lanes/components/select-field/index.js
|
529
529
|
- client/lanes/components/select-field/styles.scss
|
530
|
+
- client/lanes/components/select2/Select2.coffee
|
531
|
+
- client/lanes/components/select2/index.js
|
530
532
|
- client/lanes/extension/Base.coffee
|
531
533
|
- client/lanes/extension/EarlyExtensions.js.erb
|
532
534
|
- client/lanes/extension/Extensions.coffee
|
@@ -810,6 +812,7 @@ files:
|
|
810
812
|
- lib/lanes/access/user.rb
|
811
813
|
- lib/lanes/access/version.rb
|
812
814
|
- lib/lanes/api.rb
|
815
|
+
- lib/lanes/api/coffeescript_processor.rb
|
813
816
|
- lib/lanes/api/controller.rb
|
814
817
|
- lib/lanes/api/eco.js
|
815
818
|
- lib/lanes/api/error_formatter.rb
|
@@ -886,7 +889,6 @@ files:
|
|
886
889
|
- npm-build/package.json
|
887
890
|
- npm-build/shims/underscore.js
|
888
891
|
- npm-build/template.js
|
889
|
-
- spec/api/javascript_processor_spec.rb
|
890
892
|
- spec/command-reference-files/initial/.gitignore
|
891
893
|
- spec/command-reference-files/initial/Gemfile
|
892
894
|
- spec/command-reference-files/initial/Guardfile
|
@@ -943,6 +945,7 @@ files:
|
|
943
945
|
- spec/lanes/models/PubSubSpec.coffee
|
944
946
|
- spec/lanes/views/BaseSpec.coffee
|
945
947
|
- spec/lanes/views/FormBindingsSpec.coffee
|
948
|
+
- spec/server/api/coffeescript_processor_spec.rb
|
946
949
|
- spec/server/command_spec.rb
|
947
950
|
- spec/server/concerns/api_path_spec.rb
|
948
951
|
- spec/server/concerns/association_extensions_spec.rb
|