nali 0.2.9 → 0.3.0

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.
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