nali 0.2.2 → 0.2.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. data/README.md +19 -14
  2. data/lib/client/javascripts/nali/application.js.coffee +59 -0
  3. data/lib/client/javascripts/nali/collection.js.coffee +188 -0
  4. data/lib/{assets → client}/javascripts/nali/connection.js.coffee +32 -32
  5. data/lib/{assets → client}/javascripts/nali/controller.js.coffee +28 -30
  6. data/lib/{assets → client}/javascripts/nali/cookie.js.coffee +5 -5
  7. data/lib/client/javascripts/nali/deferred.js.coffee +16 -0
  8. data/lib/client/javascripts/nali/extensions.js.coffee +18 -0
  9. data/lib/{assets → client}/javascripts/nali/index.js +2 -1
  10. data/lib/{assets → client}/javascripts/nali/jbone.min.js +1 -1
  11. data/lib/{assets → client}/javascripts/nali/model.js.coffee +208 -118
  12. data/lib/{assets → client}/javascripts/nali/nali.js.coffee +32 -32
  13. data/lib/client/javascripts/nali/notice.js.coffee +29 -0
  14. data/lib/{assets → client}/javascripts/nali/router.js.coffee +20 -22
  15. data/lib/{assets → client}/javascripts/nali/view.js.coffee +63 -60
  16. data/lib/generator/Gemfile +8 -8
  17. data/lib/generator/app/{assets → client}/javascripts/application.js.coffee +1 -1
  18. data/lib/generator/app/{assets → client}/javascripts/controllers/homes.js.coffee +4 -4
  19. data/lib/generator/app/client/javascripts/models/home.js.coffee +5 -0
  20. data/lib/generator/app/client/javascripts/views/home/index.js.coffee +9 -0
  21. data/lib/generator/app/{assets → client}/stylesheets/application.css.sass +1 -1
  22. data/lib/generator/app/{assets → client}/stylesheets/home/index.css.sass +5 -5
  23. data/lib/generator/app/{assets → client}/stylesheets/notices/error.css.sass +1 -1
  24. data/lib/generator/app/{assets → client}/stylesheets/notices/info.css.sass +1 -1
  25. data/lib/generator/app/{assets → client}/stylesheets/notices/warning.css.sass +1 -1
  26. data/lib/generator/app/{templates → client/templates}/application.html.erb +1 -1
  27. data/lib/generator/app/{templates → client/templates}/home/index.html +1 -1
  28. data/lib/generator/app/client/templates/notice/error.html +1 -0
  29. data/lib/generator/app/client/templates/notice/info.html +1 -0
  30. data/lib/generator/app/client/templates/notice/warning.html +1 -0
  31. data/lib/generator/app/server/clients.rb +15 -0
  32. data/lib/generator/app/{controllers → server/controllers}/application_controller.rb +2 -2
  33. data/lib/generator/app/{models → server/models}/access.yml +0 -0
  34. data/lib/generator/{config → app/server}/routes.rb +3 -3
  35. data/lib/generator/config/environments/development.rb +2 -2
  36. data/lib/generator/config/environments/production.rb +4 -4
  37. data/lib/generator/config/environments/test.rb +5 -5
  38. data/lib/nali/application.rb +24 -23
  39. data/lib/nali/connection.rb +14 -31
  40. data/lib/nali/controller.rb +36 -16
  41. data/lib/nali/generator.rb +38 -23
  42. data/lib/nali/helpers.rb +3 -3
  43. data/lib/nali/model.rb +36 -22
  44. data/lib/nali/tasks.rb +16 -25
  45. data/lib/nali/version.rb +2 -2
  46. metadata +85 -86
  47. data/lib/assets/javascripts/nali/application.js.coffee +0 -28
  48. data/lib/assets/javascripts/nali/collection.js.coffee +0 -150
  49. data/lib/assets/javascripts/nali/extensions.js.coffee +0 -19
  50. data/lib/assets/javascripts/nali/notice.js.coffee +0 -14
  51. data/lib/generator/app/assets/javascripts/models/home.js.coffee +0 -3
  52. data/lib/generator/app/assets/javascripts/views/home/index.js.coffee +0 -1
  53. data/lib/generator/app/templates/notice/error.html +0 -1
  54. data/lib/generator/app/templates/notice/info.html +0 -1
  55. data/lib/generator/app/templates/notice/warning.html +0 -1
  56. data/lib/generator/config/clients.rb +0 -19
  57. data/lib/generator/config/environments/development.rb~ +0 -32
  58. data/lib/generator/config/environments/production.rb~ +0 -80
data/README.md CHANGED
@@ -1,26 +1,31 @@
1
- # Welcome to Nali
1
+ # Добро пожаловать в Nali
2
2
 
3
- Nali is the framework for developing async web applications
3
+ **Nali** - это фреймворк для разработки асинхронных веб приложений, включающий в себя веб-сервер и инструменты для создания как клиентской, так и серверной части. Серверная часть разрабатывается на языке **Ruby**, клиентская часть на **Coffeescript** (или Javascript), **Sass** (или less, scss, css) и **Html** (или erb, haml, slim)
4
4
 
5
- ## Getting Started
5
+ ## Начало работы
6
6
 
7
- 1. Install Nali at the command prompt if you haven't yet:
7
+ 1. Установите Nali с помощью командной строки:
8
8
 
9
- gem install nali
9
+ ***gem install nali***
10
10
 
11
- 2. At the command prompt, create a new Nali application:
11
+ 2. Для создания нового приложения выполните команду:
12
12
 
13
- nali new appName
13
+ ***nali new appName***
14
14
 
15
- where "appName" is the application name.
15
+ где "appName" - это имя вашего приложения
16
16
 
17
- 3. Change directory to `appName` and run:
17
+ 3. Перейдите в директорию `appName`:
18
18
 
19
- bundle install
19
+ ***cd appName***
20
+
21
+ 4. Выполните команду для установки зависимостей:
20
22
 
21
- 4. Start the web server
23
+ ***bundle install***
22
24
 
23
- bundle exec thin start
25
+ 5. Запустите веб-сервер командой:
24
26
 
25
- 5. Using a browser, go to `http://localhost:3000` and you'll see:
26
- "Welcome to Nali"
27
+ ***bundle exec thin start***
28
+
29
+ 6. Откройте браузер и перейдите по адресу `http://localhost:3000`
30
+
31
+ Вы увидите первую подготовленную страницу "Welcome to Nali"
@@ -0,0 +1,59 @@
1
+ Nali.extend Application:
2
+
3
+ domEngine: jBone.noConflict()
4
+ useWebSockets: true
5
+ wsServer: 'ws://' + window.location.host
6
+ defaultUrl: 'home'
7
+ notFoundUrl: 'home'
8
+ htmlContainer: 'body'
9
+ title: 'Application'
10
+ keepAliveDelay: 20
11
+
12
+ run: ( options ) ->
13
+ @::starting()
14
+ @[ key ] = value for key, value of options
15
+ @onReadyDOM ->
16
+ @::_ = @domEngine
17
+ @htmlContainer = @_ @htmlContainer
18
+ @setTitle @title
19
+ @Router.start()
20
+ @runConnection()
21
+
22
+ onReadyDOM: ( callback ) ->
23
+ document.addEventListener 'DOMContentLoaded', =>
24
+ document.removeEventListener 'DOMContentLoaded', arguments.callee, false
25
+ callback.call @
26
+ , false
27
+ @
28
+
29
+ runConnection: ->
30
+ if @useWebSockets
31
+ @Connection.subscribe @, 'open', @onConnectionOpen
32
+ @Connection.subscribe @, 'close', @onConnectionClose
33
+ @Connection.subscribe @, 'error', @onConnectionError
34
+ @Connection.open()
35
+ else @redirect()
36
+ @
37
+
38
+ onConnectionOpen: ->
39
+ @redirect()
40
+
41
+ onConnectionClose: ->
42
+
43
+ onConnectionError: ->
44
+
45
+ setTitle: ( @title ) ->
46
+ @titleBox ?= if ( exists = @_ 'head title' ).lenght then exists else @_( '<title>' ).appendTo 'head'
47
+ @titleBox[0].innerText = @title
48
+ @trigger 'update.title'
49
+ @
50
+
51
+
52
+
53
+
54
+
55
+
56
+
57
+
58
+
59
+
@@ -0,0 +1,188 @@
1
+ Nali.extend Collection:
2
+
3
+ toShowViews: []
4
+ visibleViews: []
5
+ length: 0
6
+
7
+ cloning: ->
8
+ @subscribeTo @Model, "create.#{ @model._name.lower() }", @onModelCreated
9
+ @subscribeTo @Model, "update.#{ @model._name.lower() }", @onModelUpdated
10
+ @adaptations = apply: [], cancel: []
11
+ @ordering = {}
12
+ @adaptCollection()
13
+ @
14
+
15
+ new: ( model, filters ) ->
16
+ @clone model: model, filters: filters
17
+
18
+ onModelCreated: ( extModel, model ) ->
19
+ @add model if not @freezed and model.isCorrect @filters
20
+ @
21
+
22
+ onModelUpdated: ( extModel, model ) ->
23
+ if model.written()
24
+ if model in @
25
+ if @freezed or model.isCorrect @filters
26
+ @reorder()
27
+ @trigger 'update.model', model
28
+ else @remove model
29
+ else if not @freezed and model.isCorrect @filters
30
+ @add model
31
+ @
32
+
33
+ onModelDestroyed: ( model ) ->
34
+ @remove model unless @freezed
35
+ @
36
+
37
+ adaptCollection: ->
38
+ for name, method of @model when /^_\w+$/.test( name ) and typeof method is 'function'
39
+ do ( name, method ) =>
40
+ @[ name = name[ 1.. ] ] = ( args... ) =>
41
+ @each ( model ) -> model[ name ] args...
42
+ @
43
+ @
44
+
45
+ adaptModel: ( model, type = 'apply' ) ->
46
+ adaptation.call @, model for adaptation in @adaptations[ type ]
47
+ @
48
+
49
+ adaptation: ( apply, cancel ) ->
50
+ @each ( model ) -> apply.call @, model
51
+ @adaptations.apply.push apply
52
+ @adaptations.cancel.unshift cancel if cancel
53
+ @
54
+
55
+ add: ( models... ) ->
56
+ for model in [].concat models...
57
+ Array::push.call @, model
58
+ @adaptModel model
59
+ @subscribeTo model, 'destroy', @onModelDestroyed
60
+ @reorder()
61
+ @trigger 'update.length.add', model
62
+ @trigger 'update.length', 'add', model
63
+ @
64
+
65
+ remove: ( model ) ->
66
+ @adaptModel model, 'cancel'
67
+ Array::splice.call @, @indexOf( model ), 1
68
+ @unsubscribeFrom model
69
+ @reorder()
70
+ @trigger 'update.length.remove', model
71
+ @trigger 'update.length', 'remove', model
72
+ @
73
+
74
+ removeAll: ->
75
+ @each ( model ) -> @remove model
76
+ @length = 0
77
+ @
78
+
79
+ each: ( callback ) ->
80
+ callback.call @, model, index for model, index in @
81
+ @
82
+
83
+ pluck: ( property ) ->
84
+ model[ property ] for model in @
85
+
86
+ indexOf: ( model ) ->
87
+ Array::indexOf.call @, model
88
+
89
+ sort: ( sorter ) ->
90
+ Array::sort.call @, sorter
91
+ @
92
+
93
+ toArray: ->
94
+ Array::slice.call @, 0
95
+
96
+ freeze: ->
97
+ @freezed = true
98
+ @
99
+
100
+ unfreeze: ->
101
+ @freezed = false
102
+ @
103
+
104
+ where: ( filters ) ->
105
+ result = []
106
+ result.push model for model in @ when model.isCorrect filters
107
+ result
108
+
109
+ order: ( @ordering ) ->
110
+ @reorder()
111
+ @
112
+
113
+ reorder: ->
114
+ if @ordering.by?
115
+ clearTimeout @ordering.timer if @ordering.timer?
116
+ @ordering.timer = setTimeout =>
117
+ if typeof @ordering.by is 'function'
118
+ @sort @ordering.by
119
+ else
120
+ @sort ( one, two ) =>
121
+ one = one[ @ordering.by ]
122
+ two = two[ @ordering.by ]
123
+ if @ordering.as is 'number'
124
+ one = + one
125
+ two = + two
126
+ if @ordering.as is 'string'
127
+ one = '' + one
128
+ two = '' + two
129
+ ( if one > two then 1 else if one < two then -1 else 0 ) * ( if @ordering.desc then -1 else 1 )
130
+ @orderViews()
131
+ delete @ordering.timer
132
+ , 5
133
+ @
134
+
135
+ orderViews: ->
136
+ if @inside
137
+ children = Array::slice.call @inside.children
138
+ children.sort ( one, two ) => @indexOf( one.view.model ) - @indexOf( two.view.model )
139
+ @inside.appendChild child for child in children
140
+ @
141
+
142
+ show: ( viewName, insertTo, isRelation = false ) ->
143
+ @adaptation ( model ) ->
144
+ view = model.view viewName
145
+ if isRelation
146
+ view.subscribeTo @, 'reset', view.hide
147
+ else unless @visible
148
+ @visible = true
149
+ @prepareViewToShow view
150
+ @hideVisibleViews()
151
+ else
152
+ @::visibleViews.push view
153
+ view.show insertTo
154
+ @inside ?= view.element[0].parentNode
155
+ , ( model ) ->
156
+ model.hide viewName
157
+ @
158
+
159
+ prepareViewToShow: ( view ) ->
160
+ unless view in @::toShowViews
161
+ @::toShowViews.push view
162
+ @prepareViewToShow layout if ( layout = view.layout() )?.childOf? 'View'
163
+ @
164
+
165
+ hideVisibleViews: ->
166
+ view.hide() for view in @::visibleViews when not( view in @::toShowViews )
167
+ @::visibleViews = @::toShowViews
168
+ @::toShowViews = []
169
+ @
170
+
171
+ first: ->
172
+ @[0]
173
+
174
+ last: ->
175
+ @[ @length - 1 ]
176
+
177
+ reset: ->
178
+ @inside = null
179
+ @adaptations.length = 0
180
+ @trigger 'reset'
181
+ @
182
+
183
+ destroy: ->
184
+ @trigger 'destroy'
185
+ @destroyObservation()
186
+ @removeAll()
187
+ @reset()
188
+ @
@@ -1,10 +1,9 @@
1
1
  Nali.extend Connection:
2
2
 
3
3
  initialize: ->
4
- @subscribeTo @Application, 'start', @open
5
- @::query = ( args... ) => @query args...
4
+ @::expand query: ( args... ) => @query args...
6
5
  @
7
-
6
+
8
7
  open: ->
9
8
  @dispatcher = new WebSocket @Application.wsServer
10
9
  @dispatcher.onopen = ( event ) => @onOpen event
@@ -13,30 +12,30 @@ Nali.extend Connection:
13
12
  @dispatcher.onmessage = ( event ) => @onMessage JSON.parse event.data
14
13
  @keepAlive()
15
14
  @
16
-
17
- connected: false
15
+
18
16
  keepAliveTimer: null
19
17
  journal: []
20
-
18
+ reconnectDelay: 0
19
+
21
20
  onOpen: ( event ) ->
22
- @connected = true
21
+ @reconnectDelay = 0
23
22
  @trigger 'open'
24
-
25
- onMessage: ( message ) ->
26
- @[ message.action ] message
27
-
28
- onClose: ( event ) ->
29
- @connected = false
30
- @trigger 'close'
31
-
23
+
32
24
  onError: ( event ) ->
33
25
  console.warn 'Connection error %O', event
34
-
26
+
27
+ onClose: ( event ) ->
28
+ @trigger 'close'
29
+ setTimeout ( => @open() ), @reconnectDelay * 100
30
+ @reconnectDelay += 1
31
+
32
+ onMessage: ( message ) ->
33
+ @[ message.action ] message
34
+
35
35
  send: ( msg ) ->
36
- @open() unless @connected
37
36
  @dispatcher.send JSON.stringify msg
38
37
  @
39
-
38
+
40
39
  keepAlive: ->
41
40
  clearTimeout @keepAliveTimer if @keepAliveTimer
42
41
  if @Application.keepAliveDelay
@@ -45,38 +44,39 @@ Nali.extend Connection:
45
44
  @send ping: true
46
45
  , @Application.keepAliveDelay * 1000
47
46
  @
48
-
47
+
49
48
  pong: ->
50
49
  @keepAlive()
51
50
  @
52
-
51
+
53
52
  sync: ( message ) ->
54
- @Model.sync message.params
53
+ @Model.sync message.params
55
54
  @
56
-
55
+
57
56
  notice: ( { model, notice, params } ) ->
58
57
  if model?
59
58
  [ model, id ] = model.split '.'
60
59
  @Model.notice model: model, id: id, notice: notice, params: params
61
- else @Notice[ notice ] params
62
- @
63
-
60
+ else @Notice[ notice ] params
61
+ @
62
+
64
63
  success: ( message ) ->
65
64
  @journal[ message.journal_id ].success? message.params
66
- delete @journal[ message.journal_id ]
65
+ delete @journal[ message.journal_id ]
67
66
  @
68
-
67
+
69
68
  failure: ( message ) ->
70
69
  @journal[ message.journal_id ].failure? message.params
71
- delete @journal[ message.journal_id ]
70
+ delete @journal[ message.journal_id ]
72
71
  @
73
-
72
+
74
73
  query: ( to, params, success, failure ) ->
74
+ return success?() unless @Application.useWebSockets
75
75
  [ controller, action ] = to.split '.'
76
76
  @journal.push callbacks = success: success, failure: failure
77
- @send
77
+ @send
78
78
  controller: controller
79
79
  action: action
80
- params: params
80
+ params: params
81
81
  journal_id: @journal.indexOf callbacks
82
- @
82
+ @
@@ -2,12 +2,13 @@ Nali.extend Controller:
2
2
 
3
3
  extension: ->
4
4
  if @_name isnt 'Controller'
5
- @prepareActions()
6
- @modelSysname = @_name.replace /s$/, ''
5
+ @prepareActions()
6
+ @modelName = @_name.replace /s$/, ''
7
7
  @
8
-
9
- actions: {}
10
-
8
+
9
+ new: ( collection, filters, params ) ->
10
+ @clone collection: collection, filters: filters, params: params
11
+
11
12
  prepareActions: ->
12
13
  @_actions = {}
13
14
  for name, action of @actions when not ( name in [ 'default', 'before', 'after' ] )
@@ -19,20 +20,20 @@ Nali.extend Controller:
19
20
  @_actions[ name ] = filters: filters, params: params, methods: [ action ]
20
21
  @prepareBefores()
21
22
  @prepareAfters()
22
- @
23
-
23
+ @
24
+
24
25
  prepareBefores: ->
25
- if @actions.before?
26
- list = @analizeFilters 'before'
26
+ if @actions?.before?
27
+ list = @analizeFilters 'before'
27
28
  @_actions[ name ].methods = actions.concat @_actions[ name ].methods for name, actions of list
28
29
  @
29
-
30
+
30
31
  prepareAfters: ->
31
- if @actions.after?
32
- list = @analizeFilters 'after'
32
+ if @actions?.after?
33
+ list = @analizeFilters 'after'
33
34
  @_actions[ name ].methods = @_actions[ name ].methods.concat actions for name, actions of list
34
35
  @
35
-
36
+
36
37
  analizeFilters: ( type ) ->
37
38
  list = {}
38
39
  for names, action of @actions[ type ]
@@ -41,30 +42,27 @@ Nali.extend Controller:
41
42
  when names is '*' then [ true, [] ]
42
43
  else [ false, names.split /\s*,\s*/ ]
43
44
  for name of @_actions when ( invert and not ( name in names ) ) or ( not invert and name in names )
44
- ( list[ name ] ?= [] ).push action
45
+ ( list[ name ] ?= [] ).push action
45
46
  list
46
-
47
+
47
48
  run: ( action, filters, params ) ->
48
- controller = @clone
49
- collection: @Model.extensions[ @modelSysname ].where filters
50
- params: params
51
- controller.runAction action
52
- if controller.stopped
53
- controller.collection.destroy()
54
- else
55
- controller.collection.show action
56
- @Router.setUrl()
49
+ collection = @Model.extensions[ @modelName ].where filters
50
+ @new( collection, filters, params ).runAction action
57
51
  @
58
-
52
+
59
53
  runAction: ( name ) ->
60
- method.call @ for method in @_actions[ name ].methods when not @stopped
54
+ method.call @ for method in @_actions[ name ].methods when not @stopped
55
+ if @stopped then @collection.destroy()
56
+ else
57
+ @collection.show name
58
+ @Router.changeUrl()
61
59
  @
62
-
60
+
63
61
  stop: ->
64
62
  @stopped = true
65
- @
66
-
63
+ @
64
+
67
65
  redirect: ( args... ) ->
68
66
  @Router.go args...
69
67
  @stop()
70
- @
68
+ @