lanes 0.1.7 → 0.1.8
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/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
|