nali 0.2.9 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -1,31 +1,26 @@
1
- # Добро пожаловать в Nali
2
-
3
- **Nali** - это фреймворк для разработки асинхронных веб приложений, включающий в себя веб-сервер и инструменты для создания как клиентской, так и серверной части. Серверная часть разрабатывается на языке **Ruby**, клиентская часть на **Coffeescript** (или Javascript), **Sass** (или less, scss, css) и **Html** (или erb, haml, slim)
4
-
5
- ## Начало работы
6
-
7
- 1. Установите Nali с помощью командной строки:
8
-
9
- ***gem install nali***
10
-
11
- 2. Для создания нового приложения выполните команду:
12
-
13
- ***nali new appName***
14
-
15
- где "appName" - это имя вашего приложения
16
-
17
- 3. Перейдите в директорию `appName`:
18
-
19
- ***cd appName***
20
-
21
- 4. Выполните команду для установки зависимостей:
22
-
23
- ***bundle install***
24
-
25
- 5. Запустите веб-сервер командой:
26
-
27
- ***bundle exec thin start***
28
-
29
- 6. Откройте браузер и перейдите по адресу `http://localhost:3000`
30
-
31
- Вы увидите первую подготовленную страницу "Welcome to Nali"
1
+ ## Добро пожаловать в Nali
2
+
3
+ **Nali** - это фреймворк для разработки асинхронных веб приложений, включающий в себя веб-сервер и инструменты для создания как клиентской, так и серверной части. Серверная часть разрабатывается на языке **Ruby**, клиентская часть на **Coffeescript** (или Javascript), **Sass** (или scss, css) и **Html** (или erb)
4
+
5
+ #### Документация
6
+
7
+ * [**Начало работы**](../../wiki/Начало-работы)
8
+ * [**Структура приложения**](../../wiki/Структура-приложения)
9
+ * **Основные компоненты**
10
+ * [Модель](../../wiki/Модель)
11
+ * [Вид](../../wiki/Вид)
12
+ * [Контроллер](../../wiki/Контроллер)
13
+ * [Коллекция](../../wiki/Коллекция)
14
+ * **Клиентская часть**
15
+ * [Базовый объект Nali](../../wiki/Nali)
16
+ * [Старт приложения](../../wiki/Nali.Application)
17
+ * [Система событий](../../wiki/Система-событий)
18
+ * [Модель уведомлений Notice](../../wiki/Nali.Notice)
19
+ * [Роутер](../../wiki/Nali.Router)
20
+ * [Соединение с сервером](../../wiki/Nali.Connection)
21
+ * [Работа с Cookie](../../wiki/Nali.Cookie)
22
+ * **Серверная часть**
23
+ * [Работа с клиентами](../../Работа с клиентами)
24
+ * [Маршрутизация](../../Маршрутизация)
25
+ * [Генератор](../../Генератор)
26
+ * [Rake задачи](../../Rake задачи)
@@ -7,20 +7,25 @@ Nali.extend Collection:
7
7
  cloning: ->
8
8
  @subscribeTo @Model, "create.#{ @model._name.lower() }", @onModelCreated
9
9
  @subscribeTo @Model, "update.#{ @model._name.lower() }", @onModelUpdated
10
+ @subscribeTo @Model, "destroy.#{ @model._name.lower() }", @onModelDestroyed
10
11
  @adaptations = apply: [], cancel: []
11
12
  @ordering = {}
12
13
  @adaptCollection()
13
- @model.each ( model ) => @add model if model.isCorrect @filters
14
+ @refilter()
15
+ @
16
+
17
+ refilter: ->
18
+ @model.each ( model ) => @add model if model.isCorrect( @filters ) and not ( model in @ )
14
19
  @
15
20
 
16
21
  new: ( model, filters ) ->
17
22
  @clone model: model, filters: filters
18
23
 
19
- onModelCreated: ( extModel, model ) ->
24
+ onModelCreated: ( model ) ->
20
25
  @add model if not @freezed and model.isCorrect @filters
21
26
  @
22
27
 
23
- onModelUpdated: ( extModel, model ) ->
28
+ onModelUpdated: ( model ) ->
24
29
  if model.written()
25
30
  if model in @
26
31
  if @freezed or model.isCorrect @filters
@@ -32,7 +37,7 @@ Nali.extend Collection:
32
37
  @
33
38
 
34
39
  onModelDestroyed: ( model ) ->
35
- @remove model unless @freezed
40
+ @remove model if model in @ and not @freezed
36
41
  @
37
42
 
38
43
  adaptCollection: ->
@@ -57,7 +62,6 @@ Nali.extend Collection:
57
62
  for model in [].concat models...
58
63
  Array::push.call @, model
59
64
  @adaptModel model
60
- @subscribeTo model, 'destroy', @onModelDestroyed
61
65
  @reorder()
62
66
  @trigger 'update.length.add', model
63
67
  @trigger 'update.length', 'add', model
@@ -100,6 +104,7 @@ Nali.extend Collection:
100
104
 
101
105
  unfreeze: ->
102
106
  @freezed = false
107
+ @refilter()
103
108
  @
104
109
 
105
110
  where: ( filters ) ->
@@ -156,6 +161,10 @@ Nali.extend Collection:
156
161
  model.hide viewName
157
162
  @
158
163
 
164
+ hide: ( viewName, delay ) ->
165
+ model.hide viewName, delay for model in @
166
+ @
167
+
159
168
  prepareViewToShow: ( view ) ->
160
169
  unless view in @::toShowViews
161
170
  @::toShowViews.push view
@@ -53,11 +53,11 @@ Nali.extend Connection:
53
53
  @Model.sync message.params
54
54
  @
55
55
 
56
- notice: ( { model, notice, params } ) ->
57
- if model?
56
+ callMethod: ( { model, method, params } ) ->
57
+ if model is 'Notice' then @Notice[ method ] params
58
+ else
58
59
  [ model, id ] = model.split '.'
59
- @Model.notice model: model, id: id, notice: notice, params: params
60
- else @Notice[ notice ] params
60
+ @Model.callStackAdd model: model, id: id, method: method, params: params
61
61
  @
62
62
 
63
63
  success: ( message ) ->
@@ -0,0 +1 @@
1
+ (function(e,t){if(typeof define==="function"&&define.amd){define(t)}else{e.form2js=t()}})(this,function(){"use strict";function e(e,r,i,s,o,u){u=u?true:false;if(typeof i=="undefined"||i==null)i=true;if(typeof r=="undefined"||r==null)r=".";if(arguments.length<5)o=false;e=typeof e=="string"?document.getElementById(e):e;var a=[],f,l=0;if(e.constructor==Array||typeof NodeList!="undefined"&&e.constructor==NodeList){while(f=e[l++]){a=a.concat(n(f,s,o,u))}}else{a=n(e,s,o,u)}return t(a,i,r)}function t(e,t,n){var r={},i={},s,o,u,a,f,l,c,h,p,d,v,m,g;for(s=0;s<e.length;s++){f=e[s].value;if(t&&(f===""||f===null))continue;m=e[s].name;g=m.split(n);l=[];c=r;h="";for(o=0;o<g.length;o++){v=g[o].split("][");if(v.length>1){for(u=0;u<v.length;u++){if(u==0){v[u]=v[u]+"]"}else if(u==v.length-1){v[u]="["+v[u]}else{v[u]="["+v[u]+"]"}d=v[u].match(/([a-z_]+)?\[([a-z_][a-z0-9_]+?)\]/i);if(d){for(a=1;a<d.length;a++){if(d[a])l.push(d[a])}}else{l.push(v[u])}}}else l=l.concat(v)}for(o=0;o<l.length;o++){v=l[o];if(v.indexOf("[]")>-1&&o==l.length-1){p=v.substr(0,v.indexOf("["));h+=p;if(!c[p])c[p]=[];c[p].push(f)}else if(v.indexOf("[")>-1){p=v.substr(0,v.indexOf("["));d=v.replace(/(^([a-z_]+)?\[)|(\]$)/gi,"");h+="_"+p+"_"+d;if(!i[h])i[h]={};if(p!=""&&!c[p])c[p]=[];if(o==l.length-1){if(p==""){c.push(f);i[h][d]=c[c.length-1]}else{c[p].push(f);i[h][d]=c[p][c[p].length-1]}}else{if(!i[h][d]){if(/^[0-9a-z_]+\[?/i.test(l[o+1]))c[p].push({});else c[p].push([]);i[h][d]=c[p][c[p].length-1]}}c=i[h][d]}else{h+=v;if(o<l.length-1){if(!c[v])c[v]={};c=c[v]}else{c[v]=f}}}}return r}function n(e,t,n,s){var o=i(e,t,n,s);return o.length>0?o:r(e,t,n,s)}function r(e,t,n,r){var s=[],o=e.firstChild;while(o){s=s.concat(i(o,t,n,r));o=o.nextSibling}return s}function i(e,t,n,i){if(e.disabled&&!i)return[];var u,a,f,l=s(e,n);u=t&&t(e);if(u&&u.name){f=[u]}else if(l!=""&&e.nodeName.match(/INPUT|TEXTAREA/i)){a=o(e,i);if(null===a){f=[]}else{f=[{name:l,value:a}]}}else if(l!=""&&e.nodeName.match(/SELECT/i)){a=o(e,i);f=[{name:l.replace(/\[\]$/,""),value:a}]}else{f=r(e,t,n,i)}return f}function s(e,t){if(e.name&&e.name!="")return e.name;else if(t&&e.id&&e.id!="")return e.id;else return""}function o(e,t){if(e.disabled&&!t)return null;switch(e.nodeName){case"INPUT":case"TEXTAREA":switch(e.type.toLowerCase()){case"radio":if(e.checked&&e.value==="false")return false;case"checkbox":if(e.checked&&e.value==="true")return true;if(!e.checked&&e.value==="true")return false;if(e.checked)return e.value;break;case"button":case"reset":case"submit":case"image":return"";break;default:return e.value;break}break;case"SELECT":return u(e);break;default:break}return null}function u(e){var t=e.multiple,n=[],r,i,s;if(!t)return e.value;for(r=e.getElementsByTagName("option"),i=0,s=r.length;i<s;i++){if(r[i].selected)n.push(r[i].value)}return n}return e})
@@ -1,4 +1,5 @@
1
1
  //= require ./jbone.min
2
+ //= require ./form2js.min
2
3
  //= require ./extensions
3
4
  //= require ./nali
4
5
  //= require ./deferred
@@ -14,7 +14,7 @@ Nali.extend Model:
14
14
  tables: {}
15
15
  attributes: {}
16
16
  updated: 0
17
- noticesWait: []
17
+ callStack: []
18
18
  destroyed: false
19
19
 
20
20
  adapt: ->
@@ -36,18 +36,18 @@ Nali.extend Model:
36
36
  unless @[ hideMethod = 'hide' + shortCap ]? then @[ hideMethod ] = -> @hide short
37
37
  @
38
38
 
39
- notice: ( params ) ->
40
- # добавляет уведомление в очередь на выполнение, запускает выполнение очереди
41
- @noticesWait.push params
42
- @runNotices()
39
+ callStackAdd: ( params ) ->
40
+ # добавляет задачу в очередь на выполнение, запускает выполнение очереди
41
+ @callStack.push params
42
+ @runStack()
43
43
  @
44
44
 
45
- runNotices: ->
46
- # запускает выполнение уведомлений на существующих моделях
47
- for item, index in @noticesWait[ 0.. ]
45
+ runStack: ->
46
+ # запускает выполнение задач у существующих моделей
47
+ for item, index in @callStack[ 0.. ]
48
48
  if model = @extensions[ item.model ].find item.id
49
- model[ item.notice ] item.params
50
- @noticesWait.splice @noticesWait.indexOf( item ), 1
49
+ model[ item.method ] item.params
50
+ @callStack.splice @callStack.indexOf( item ), 1
51
51
  @
52
52
 
53
53
  # работа с моделями
@@ -58,13 +58,6 @@ Nali.extend Model:
58
58
  @setRelations()
59
59
  @
60
60
 
61
- force: ( params = {} ) ->
62
- # создает новую модель с заданными атрибутами
63
- attributes = @defaultAttributes()
64
- attributes[ name ] = value for name, value of params
65
- attributes[ name ] = @normalizeValue value for name, value of attributes
66
- @clone( attributes: attributes ).accessing()
67
-
68
61
  save: ( success, failure ) ->
69
62
  # отправляет на сервер запрос на сохранение модели, вызывает success в случае успеха и failure при неудаче
70
63
  if @isValid()
@@ -109,7 +102,7 @@ Nali.extend Model:
109
102
  @table.push @
110
103
  @onCreate?()
111
104
  @Model.trigger "create.#{ @_name.lower() }", @
112
- @Model.runNotices()
105
+ @Model.runStack()
113
106
  @
114
107
 
115
108
  remove: ->
@@ -119,13 +112,16 @@ Nali.extend Model:
119
112
  delete @table.index[ @id ]
120
113
  @table.splice @table.indexOf( @ ), 1
121
114
  @trigger 'destroy'
115
+ @Model.trigger "destroy.#{ @_name.lower() }", @
122
116
  @onDestroy?()
123
117
  @unsubscribeAll()
124
118
  @
125
119
 
126
120
  new: ( attributes ) ->
127
121
  # создает модель, не сохраняя её на сервере
128
- @force attributes
122
+ model = @clone( attributes: @defaultAttributes() ).accessing()
123
+ model[ name ] = @normalizeValue value for name, value of attributes
124
+ model
129
125
 
130
126
  create: ( attributes, success, failure ) ->
131
127
  # создает модель, и сохраняет её на сервере, вызывает success в случае успеха и failure при неудаче
@@ -136,7 +132,7 @@ Nali.extend Model:
136
132
  if not updated or updated > @updated
137
133
  @created = created if created
138
134
  changed = []
139
- changed.push name for name, value of attributes when @updateAttribute name, value
135
+ changed.push name for name, value of attributes when @updateProperty name, value
140
136
  if changed.length
141
137
  @updated = updated if updated
142
138
  @onUpdate? changed
@@ -144,8 +140,8 @@ Nali.extend Model:
144
140
  @Model.trigger "update.#{ @_name.lower() }", @
145
141
  @
146
142
 
147
- updateAttribute: ( name, value ) ->
148
- # обновляет один атрибут модели, проверяя его валидность, генерирует событие update.attributeName
143
+ updateProperty: ( name, value ) ->
144
+ # обновляет один атрибут модели, проверяя его валидность, генерирует событие update.propertyName
149
145
  value = @normalizeValue value
150
146
  if @[ name ] isnt value and @isValidAttributeValue( name, value )
151
147
  @[ name ] = value
@@ -172,12 +168,7 @@ Nali.extend Model:
172
168
 
173
169
  where: ( filters ) ->
174
170
  # возвращает коллекцию моделей соответствующих фильтру
175
- collection = @Collection.new @, filters
176
- if @forced and not collection.length
177
- attributes = {}
178
- attributes[ key ] = value for key, value of filters when typeof value in [ 'number', 'string' ]
179
- collection.add @new attributes
180
- collection
171
+ @Collection.new @, filters
181
172
 
182
173
  all: ->
183
174
  # возвращает коллекцию всех моделей
@@ -203,8 +194,8 @@ Nali.extend Model:
203
194
  attributes = id: @guid()
204
195
  for name, value of @attributes
205
196
  if value instanceof Object
206
- attributes[ name ] = if value.default? then value.default else null
207
- else attributes[ name ] = value
197
+ attributes[ name ] = if value.default? then @normalizeValue value.default else null
198
+ else attributes[ name ] = @normalizeValue value
208
199
  attributes
209
200
 
210
201
  normalizeValue: ( value ) ->
@@ -333,8 +324,8 @@ Nali.extend Model:
333
324
  @[ name ] = model.where correct: ->
334
325
  return true for model in @[ through ] when model[ key ] is @
335
326
  false
336
- @[ name ].subscribeTo @[ through ], 'update.length.add', ( collection, model ) -> @add model[ key ]
337
- @[ name ].subscribeTo @[ through ], 'update.length.remove', ( collection, model ) -> @remove model[ key ]
327
+ @[ name ].subscribeTo @[ through ], 'update.length.add', ( model ) -> @add model[ key ]
328
+ @[ name ].subscribeTo @[ through ], 'update.length.remove', ( model ) -> @remove model[ key ]
338
329
  @[ name ]
339
330
  @
340
331
 
@@ -354,10 +345,10 @@ Nali.extend Model:
354
345
  # функция возвращает объект вида при успехе либо null при неудаче
355
346
  if ( view = @view( name ) )? then view.show insertTo else null
356
347
 
357
- hide: ( name ) ->
348
+ hide: ( name, delay ) ->
358
349
  # удаляет html-код вида со страницы
359
350
  # функция возвращает объект вида при успехе либо null при неудаче
360
- if ( view = @view( name ) )? then view.hide() else null
351
+ if ( view = @view( name ) )? then view.hide delay else null
361
352
 
362
353
  # валидации
363
354
 
@@ -390,12 +381,14 @@ Nali.extend Model:
390
381
 
391
382
  isValidAttributeValue: ( name, value ) ->
392
383
  # проверяет валидно ли значение для определенного атрибута модели, вызывается при проверке
393
- # валидности модели, а также в методе updateAttribute() перед изменением значения атрибута, если значение
384
+ # валидности модели, а также в методе updateProperty() перед изменением значения атрибута, если значение
394
385
  # валидно то вызов model.isValidAttributeValue( name, value )? вернет true, иначе false
395
386
  for validation, tester of @validations when ( filter = @::attributes[ name ]?[ validation ] )?
396
387
  unless tester.call @, value, filter
397
388
  console.warn 'Attribute %s of model %O has not validate %s', name, @, validation
398
- for type in [ 'info', 'warning', 'error' ] when ( message = @::attributes[ name ][ type ] )?
399
- @Notice[ type ] message: message
389
+ if notice = @::attributes[ name ].notice
390
+ for type, params of notice
391
+ if @Notice[ type ]? then @Notice[ type ] params
392
+ else console.warn 'Unknown Notice type "%s"', type
400
393
  return false
401
394
  true
@@ -128,5 +128,5 @@ window.Nali =
128
128
  @
129
129
 
130
130
  trigger: ( event, args... ) ->
131
- item[2].call item[0], @, args... for item in @observers[..] when item[1] is event
131
+ item[2].call item[0], args... for item in @observers[..] when item[1] is event
132
132
  @
@@ -2,19 +2,16 @@ Nali.Model.extend Notice:
2
2
 
3
3
  initialize: ->
4
4
  @::::expand Notice: @
5
+ @addMethods()
5
6
 
6
7
  prepare: ( params ) ->
7
8
  params = message: params if typeof params is 'string'
8
9
  params
9
10
 
10
- info: ( params ) ->
11
- @new( @prepare params ).show 'info'
12
-
13
- warning: ( params ) ->
14
- @new( @prepare params ).show 'warning'
15
-
16
- error: ( params ) ->
17
- @new( @prepare params ).show 'error'
11
+ addMethods: ->
12
+ for name of @views
13
+ do ( name ) =>
14
+ @[ name ] = ( params ) => @new( @prepare params ).show name
18
15
 
19
16
 
20
17
  Nali.View.extend
@@ -28,7 +28,7 @@ Nali.extend View:
28
28
  @subscribeTo source, event, @onSourceUpdated
29
29
 
30
30
  insertTo: ->
31
- if ( layout = @layout() )?.childOf? 'View' then layout.show().element.find '.yield'
31
+ if ( layout = @layout() )?.childOf? 'View' then layout.show().yield
32
32
  else @Application.htmlContainer
33
33
 
34
34
  draw: ->
@@ -45,6 +45,7 @@ Nali.extend View:
45
45
  @subscribeTo @model, 'destroy', @onSourceDestroyed
46
46
  @element.appendTo insertTo
47
47
  setTimeout ( => @onShow() ), 5 if @onShow?
48
+ @trigger 'show'
48
49
  @visible = true
49
50
  @runModelCallback 'afterShow'
50
51
  else
@@ -54,18 +55,19 @@ Nali.extend View:
54
55
  hide: ( delay = 0 ) ->
55
56
  if @visible
56
57
  @runModelCallback 'beforeHide'
57
- @hideDelay = delay if typeof( delay ) is 'number' and delay
58
58
  @onHide?()
59
59
  @trigger 'hide'
60
60
  @runAssistants 'hide'
61
- @hideElement()
61
+ @hideElement delay or @hideDelay
62
62
  @destroyObservation()
63
63
  @visible = false
64
64
  @runModelCallback 'afterHide'
65
65
  @
66
66
 
67
- hideElement: ->
68
- if @hideDelay? then setTimeout ( => @removeElement() ), @hideDelay else @removeElement()
67
+ hideElement: ( delay ) ->
68
+ if delay and typeof( delay ) is 'number'
69
+ setTimeout ( => @removeElement() ), delay
70
+ else @removeElement()
69
71
  @
70
72
 
71
73
  removeElement: ->
@@ -83,7 +85,7 @@ Nali.extend View:
83
85
 
84
86
  runForm: ( event ) ->
85
87
  event.preventDefault()
86
- @runUrl event.currentTarget.getAttribute( 'action' ), @formToHash event.currentTarget
88
+ @runUrl event.currentTarget.getAttribute( 'action' ), form2js event.currentTarget, '.', false
87
89
  @
88
90
 
89
91
  runUrl: ( url, params ) ->
@@ -100,7 +102,7 @@ Nali.extend View:
100
102
 
101
103
  parseUrlSegments: ( segments ) ->
102
104
  params = []
103
- for segment in segments
105
+ for segment in segments when segment isnt ''
104
106
  [ name, value ] = segment.split ':'
105
107
  if value
106
108
  last = params[ params.length - 1 ]
@@ -109,17 +111,6 @@ Nali.extend View:
109
111
  else params.push name
110
112
  params
111
113
 
112
- formToHash: ( form ) ->
113
- params = {}
114
- for element in form.elements
115
- if name = element.name or element.id
116
- property = ( keys = name.match /[^\[\]]+/g ).pop()
117
- target = params
118
- for key in keys
119
- target = if target[ key ] instanceof Object then target[ key ] else target[ key ] = {}
120
- target[ property ] = element.value
121
- params
122
-
123
114
  parseEvents: ->
124
115
  @eventsMap = []
125
116
  if @events
@@ -166,7 +157,6 @@ Nali.extend View:
166
157
  if container = document.querySelector '#' + @_name.underscore()
167
158
  @template = container.innerHTML.trim().replace( /\s+/g, ' ' )
168
159
  .replace( /({\s*\+.+?\s*})/g, ' <assist>$1</assist>' )
169
- .replace( /{\s*yield\s*}/g, '<div class="yield"></div>' )
170
160
  unless RegExp( "^<[^>]+" + @_name ).test @template
171
161
  @template = "<div class=\"#{ @_name }\">#{ @template }</div>"
172
162
  @parseAssistants()
@@ -184,7 +174,9 @@ Nali.extend View:
184
174
 
185
175
  scanAssistants: ( node, path = [] ) ->
186
176
  if node.nodeType is 3
187
- if /^{\s*\w+ of @\w*\s*}$/.test( node.textContent.trim() ) and node.parentNode.childNodes.length is 1
177
+ if /{\s*yield\s*}/.test( node.textContent.trim() ) and node.parentNode.childNodes.length is 1
178
+ @assistantsMap.push nodepath: path, type: 'Yield'
179
+ else if /^{\s*\w+ of @\w*\s*}$/.test( node.textContent.trim() ) and node.parentNode.childNodes.length is 1
188
180
  @assistantsMap.push nodepath: path, type: 'Relation'
189
181
  else if /{\s*.+?\s*}/.test node.textContent
190
182
  @assistantsMap.push nodepath: path, type: 'Text'
@@ -238,7 +230,7 @@ Nali.extend View:
238
230
  _node = @_ node
239
231
 
240
232
  updateSource = ->
241
- ( params = {} )[ property ] = node.value
233
+ ( params = {} )[ property ] = if node.type is 'checkbox' and !node.checked then null else node.value
242
234
  source.update params
243
235
  source.save() unless node.form?
244
236
 
@@ -251,7 +243,7 @@ Nali.extend View:
251
243
  when node.type in [ 'checkbox', 'radio' ]
252
244
  [
253
245
  -> node.checked = source[ property ] + '' is node.value
254
- -> _node.on 'change', => updateSource.call @ if node.checked is true
246
+ -> _node.on 'change', => updateSource.call @ if node.type is 'checkbox' or node.checked is true
255
247
  ]
256
248
  when node.type is 'select-one'
257
249
  [
@@ -268,6 +260,9 @@ Nali.extend View:
268
260
  _node.off 'change'
269
261
  @
270
262
 
263
+ addYieldAssistant: ( node ) ->
264
+ ( @yield = node.parentNode ).removeChild node
265
+
271
266
  addRelationAssistant: ( node ) ->
272
267
  [ match, name, chain ] = node.textContent.match /{\s*(\w+) of @(\w*)\s*}/
273
268
  ( insertTo = node.parentNode ).removeChild node
@@ -7,14 +7,16 @@ module EventMachine
7
7
  @watches = {}
8
8
  end
9
9
 
10
- def []( name )
10
+ def storage
11
11
  @storage ||= {}
12
- @storage[ name ] or nil
12
+ end
13
+
14
+ def []( name = nil )
15
+ name ? ( storage[ name ] or nil ) : storage
13
16
  end
14
17
 
15
- def []=( name, value = false )
16
- @storage ||= {}
17
- @storage[ name ] = value
18
+ def []=( name, value )
19
+ storage[ name ] = value
18
20
  end
19
21
 
20
22
  def watches
@@ -56,16 +58,13 @@ module EventMachine
56
58
  end
57
59
  end
58
60
 
59
- def notice( name, *args )
60
- message = { action: :notice, notice: name }
61
- if args[0].is_a?( ActiveRecord::Base )
62
- model, params = args
63
- message[ :model ] = "#{ model.class.name }.#{ model.id }"
64
- else
65
- params = args[0]
66
- end
67
- message[ :params ] = params
68
- send_json message
61
+ def call_method( method, model, params = nil )
62
+ model = "#{ model.class.name }.#{ model.id }" if model.is_a?( ActiveRecord::Base )
63
+ send_json action: 'callMethod', model: model, method: method, params: params
64
+ end
65
+
66
+ def notice( method, params = nil )
67
+ call_method method, 'Notice', params
69
68
  end
70
69
 
71
70
  def info( params )
@@ -33,10 +33,10 @@ module Nali
33
33
  end
34
34
 
35
35
  def save
36
- params[ :id ].to_i.to_s == params[ :id ].to_s ? update : create
36
+ params[ :id ].to_i.to_s == params[ :id ].to_s ? _update : _create
37
37
  end
38
38
 
39
- def create
39
+ def _create
40
40
  model = model_class.new params
41
41
  model.access_action( :create, client ) do |options|
42
42
  permit_params options
@@ -47,7 +47,7 @@ module Nali
47
47
  end
48
48
  end
49
49
 
50
- def update
50
+ def _update
51
51
  if model = model_class.find_by_id( params[ :id ] )
52
52
  model.access_action( :update, client ) do |options|
53
53
  permit_params options
@@ -23,10 +23,16 @@ module Nali
23
23
  dirs << File.join( target_path, 'db' )
24
24
  dirs << File.join( target_path, 'db/migrate' )
25
25
  dirs << File.join( target_path, 'lib' )
26
+ dirs << File.join( target_path, 'lib/client' )
27
+ dirs << File.join( target_path, 'lib/client/javascripts' )
28
+ dirs << File.join( target_path, 'lib/client/stylesheets' )
26
29
  dirs << File.join( target_path, 'public' )
27
30
  dirs << File.join( target_path, 'public/client' )
28
31
  dirs << File.join( target_path, 'tmp' )
29
32
  dirs << File.join( target_path, 'vendor' )
33
+ dirs << File.join( target_path, 'vendor/client' )
34
+ dirs << File.join( target_path, 'vendor/client/javascripts' )
35
+ dirs << File.join( target_path, 'vendor/client/stylesheets' )
30
36
  dirs << File.join( target_path, 'config/initializers' )
31
37
  dirs.each { |path| Dir.mkdir( path ) unless Dir.exists?( path ) }
32
38
  puts "Application #{ name } created"
@@ -116,6 +122,8 @@ end"
116
122
 
117
123
  helpers: {}
118
124
 
125
+ onDraw: ->
126
+
119
127
  onShow: ->
120
128
 
121
129
  onHide: ->"
data/lib/nali/model.rb CHANGED
@@ -38,7 +38,9 @@ module Nali
38
38
  relations << value
39
39
  elsif value.is_a?( ActiveRecord::Base )
40
40
  relations << value
41
- params[ :attributes ][ option.to_s + '_id' ] = value.id
41
+ if reflection = self.class.reflections[ option ] and reflection.macro == :belongs_to
42
+ params[ :attributes ][ option.to_s + '_id' ] = value.id
43
+ end
42
44
  else
43
45
  params[ :attributes ][ option ] = value
44
46
  end
@@ -64,9 +66,9 @@ module Nali
64
66
  watches.flatten.each { |client| client.watch self }
65
67
  clients.each { |client| client.sync self if client.watch?( self ) }
66
68
  end
67
-
68
- def notice( name, params )
69
- clients.each { |client| client.notice self, name, params if client.watch?( self ) }
69
+
70
+ def call_method( name, params )
71
+ clients.each { |client| client.call_method self, name, params if client.watch?( self ) }
70
72
  end
71
73
 
72
74
  private
data/lib/nali/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  module Nali
2
2
 
3
- VERSION = '0.2.9'
3
+ VERSION = '0.3.0'
4
4
 
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nali
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.9
4
+ version: 0.3.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2014-11-21 00:00:00.000000000 Z
12
+ date: 2014-11-28 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: thin
@@ -208,6 +208,7 @@ files:
208
208
  - lib/client/javascripts/nali/collection.js.coffee
209
209
  - lib/client/javascripts/nali/application.js.coffee
210
210
  - lib/client/javascripts/nali/index.js
211
+ - lib/client/javascripts/nali/form2js.min.js
211
212
  - lib/client/javascripts/nali/connection.js.coffee
212
213
  - lib/nali.rb
213
214
  - lib/nali/extensions.rb
@@ -230,10 +231,10 @@ files:
230
231
  - lib/generator/app/client/templates/notice/warning.html
231
232
  - lib/generator/app/client/templates/notice/info.html
232
233
  - lib/generator/app/client/templates/home/index.html
234
+ - lib/generator/app/client/stylesheets/notice/info.css.sass
235
+ - lib/generator/app/client/stylesheets/notice/error.css.sass
236
+ - lib/generator/app/client/stylesheets/notice/warning.css.sass
233
237
  - lib/generator/app/client/stylesheets/home/index.css.sass
234
- - lib/generator/app/client/stylesheets/notices/info.css.sass
235
- - lib/generator/app/client/stylesheets/notices/error.css.sass
236
- - lib/generator/app/client/stylesheets/notices/warning.css.sass
237
238
  - lib/generator/app/client/stylesheets/application.css.sass
238
239
  - lib/generator/app/server/models/access.yml
239
240
  - lib/generator/app/server/routes.rb