engine2 1.0.4 → 1.0.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (122) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +0 -0
  3. data/Rakefile +1 -1
  4. data/app/{engine2actions.coffee → actions.coffee} +192 -142
  5. data/app/app.coffee +0 -0
  6. data/app/app.css +4 -0
  7. data/app/engine2.coffee +87 -175
  8. data/app/modal.coffee +133 -0
  9. data/bower.json +2 -1
  10. data/conf/message.yaml +0 -0
  11. data/conf/message_pl.yaml +0 -0
  12. data/config.coffee +11 -2
  13. data/engine2.gemspec +2 -2
  14. data/lib/engine2.rb +12 -10
  15. data/lib/engine2/action.rb +1290 -134
  16. data/lib/engine2/{meta/array_meta.rb → action/array.rb} +4 -3
  17. data/lib/engine2/{meta/decode_meta.rb → action/decode.rb} +16 -15
  18. data/lib/engine2/action/delete.rb +65 -0
  19. data/lib/engine2/action/form.rb +16 -0
  20. data/lib/engine2/{meta/infra_meta.rb → action/infra.rb} +118 -85
  21. data/lib/engine2/action/link.rb +117 -0
  22. data/lib/engine2/{meta/list_meta.rb → action/list.rb} +61 -62
  23. data/lib/engine2/action/save.rb +30 -0
  24. data/lib/engine2/action/view.rb +8 -0
  25. data/lib/engine2/action_node.rb +221 -0
  26. data/lib/engine2/core.rb +120 -77
  27. data/lib/engine2/handler.rb +9 -10
  28. data/lib/engine2/model.rb +4 -20
  29. data/lib/engine2/models/Files.rb +2 -1
  30. data/lib/engine2/models/UserInfo.rb +6 -3
  31. data/lib/engine2/post_bootstrap.rb +3 -2
  32. data/lib/engine2/pre_bootstrap.rb +1 -0
  33. data/lib/engine2/scheme.rb +98 -47
  34. data/lib/engine2/templates.rb +1 -0
  35. data/lib/engine2/type_info.rb +6 -4
  36. data/lib/engine2/version.rb +2 -1
  37. data/package.json +12 -10
  38. data/public/favicon.ico +0 -0
  39. data/public/img/ajax-loader-dark.gif +0 -0
  40. data/public/img/ajax-loader.gif +0 -0
  41. data/views/fields/blob.slim +0 -0
  42. data/views/fields/bs_select.slim +0 -0
  43. data/views/fields/bsselect_picker.slim +0 -0
  44. data/views/fields/bsselect_picker_opt.slim +0 -0
  45. data/views/fields/checkbox.slim +0 -0
  46. data/views/fields/checkbox_buttons.slim +0 -0
  47. data/views/fields/checkbox_buttons_opt.slim +0 -0
  48. data/views/fields/currency.slim +0 -0
  49. data/views/fields/date.slim +0 -0
  50. data/views/fields/date_range.slim +0 -0
  51. data/views/fields/date_time.slim +0 -0
  52. data/views/fields/datetime.slim +0 -0
  53. data/views/fields/decimal.slim +0 -0
  54. data/views/fields/decimal_date.slim +0 -0
  55. data/views/fields/decimal_time.slim +0 -0
  56. data/views/fields/email.slim +0 -0
  57. data/views/fields/file_store.slim +7 -7
  58. data/views/fields/input_text.slim +0 -0
  59. data/views/fields/integer.slim +0 -0
  60. data/views/fields/list_bsselect.slim +0 -0
  61. data/views/fields/list_bsselect_opt.slim +0 -0
  62. data/views/fields/list_buttons.slim +0 -0
  63. data/views/fields/list_buttons_opt.slim +0 -0
  64. data/views/fields/list_select.slim +0 -0
  65. data/views/fields/list_select_opt.slim +0 -0
  66. data/views/fields/password.slim +0 -0
  67. data/views/fields/radio_checkbox.slim +0 -0
  68. data/views/fields/scaffold.slim +0 -0
  69. data/views/fields/scaffold_picker.slim +0 -0
  70. data/views/fields/select_picker.slim +0 -0
  71. data/views/fields/select_picker_opt.slim +0 -0
  72. data/views/fields/text_area.slim +1 -0
  73. data/views/fields/time.slim +0 -0
  74. data/views/fields/typeahead_picker.slim +0 -0
  75. data/views/index.slim +3 -3
  76. data/views/infra/index.slim +0 -0
  77. data/views/infra/inspect.slim +20 -0
  78. data/views/modals/close_m.slim +0 -0
  79. data/views/modals/confirm_m.slim +0 -0
  80. data/views/modals/empty_m.slim +0 -0
  81. data/views/modals/menu_m.slim +1 -1
  82. data/views/modals/yes_no_m.slim +0 -0
  83. data/views/panels/menu_m.slim +1 -1
  84. data/views/scaffold/confirm.slim +0 -0
  85. data/views/scaffold/fields.slim +0 -0
  86. data/views/scaffold/form.slim +0 -0
  87. data/views/scaffold/form_collapse.slim +0 -0
  88. data/views/scaffold/form_tabs.slim +0 -0
  89. data/views/scaffold/list.slim +0 -0
  90. data/views/scaffold/message.slim +0 -0
  91. data/views/scaffold/search.slim +0 -0
  92. data/views/scaffold/search_collapse.slim +0 -0
  93. data/views/scaffold/search_tabs.slim +0 -0
  94. data/views/scaffold/view.slim +0 -0
  95. data/views/scaffold/view_collapse.slim +0 -0
  96. data/views/scaffold/view_tabs.slim +0 -0
  97. data/views/search_fields/bsmselect_picker.slim +0 -0
  98. data/views/search_fields/bsselect_picker.slim +0 -0
  99. data/views/search_fields/checkbox.slim +0 -0
  100. data/views/search_fields/checkbox2.slim +0 -0
  101. data/views/search_fields/checkbox_buttons.slim +0 -0
  102. data/views/search_fields/date_range.slim +0 -0
  103. data/views/search_fields/decimal_date_range.slim +0 -0
  104. data/views/search_fields/input_text.slim +0 -0
  105. data/views/search_fields/integer.slim +0 -0
  106. data/views/search_fields/integer_range.slim +0 -0
  107. data/views/search_fields/list_bsmselect.slim +0 -0
  108. data/views/search_fields/list_bsselect.slim +0 -0
  109. data/views/search_fields/list_buttons.slim +0 -0
  110. data/views/search_fields/list_select.slim +0 -0
  111. data/views/search_fields/scaffold_picker.slim +0 -0
  112. data/views/search_fields/select_picker.slim +0 -0
  113. data/views/search_fields/typeahead_picker.slim +0 -0
  114. metadata +41 -42
  115. data/lib/engine2/meta.rb +0 -1216
  116. data/lib/engine2/meta/delete_meta.rb +0 -60
  117. data/lib/engine2/meta/form_meta.rb +0 -15
  118. data/lib/engine2/meta/link_meta.rb +0 -134
  119. data/lib/engine2/meta/save_meta.rb +0 -50
  120. data/lib/engine2/meta/view_meta.rb +0 -7
  121. data/public/__sinatra__/404.png +0 -0
  122. data/public/__sinatra__/500.png +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 6174073612b4abd1d1a7c2fefbbf071874c2c566
4
- data.tar.gz: 081dee914669d77bb0a9e32d13c219612aa79d75
3
+ metadata.gz: 61ac9190b96b7053391913f8121f1df0bc1967c0
4
+ data.tar.gz: b532a2ca2828607b2068450761cc55a77d43f597
5
5
  SHA512:
6
- metadata.gz: 5631fd58edca95f2c3966ccc240a29b0089c78e7a80b9d3a7e5e239e2a001e0a02f7baa9ed6cdff6a0d98f061022f02d0768282513b457bf6e9fd180c8adf96e
7
- data.tar.gz: bcc3a19a71996a4c2e8f5f2d511354dc1085de8bdd5eacce667cbe1f24a91587dee04892fb22d51276f7a152a4b21c72681e90f379731ad2f1d546f9c5940294
6
+ metadata.gz: 3afb80475e3f7cad3bed23163f0b03f1d54d9268a46749c5e7d9dbc5aa77cbb0859b83592094e50b8178492ff3656a98eb31123be8f56a99962bac033dc20d1a
7
+ data.tar.gz: a7d20b040fd8a85373a9328508710064fa403103b2c661d2d2d71eaec148910397e2d2ddcffb0aea6712eab3bb3bf49943f496e87bd413997d6e25e1d2586bed
data/Gemfile CHANGED
File without changes
data/Rakefile CHANGED
@@ -10,7 +10,7 @@ task :compile_slim do
10
10
  end
11
11
  end
12
12
 
13
- open("app/engine2templates.js", "wb") << <<-EOF
13
+ open("app/templates.js", "wb") << <<-EOF
14
14
  angular.module('Engine2').run(['$templateCache', function($templateCache) {
15
15
  #{slims.join("\n")}
16
16
  }]);
@@ -8,7 +8,7 @@ angular.module('Engine2')
8
8
  throw "Invalid action path: '#{action_attr}'" unless action_names
9
9
  action_names = action_names.split('/') if _.isString(action_names)
10
10
  create = (action) ->
11
- action.create_action_path(action_names, $scope, $element).then (act) -> act.invoke() if $attrs.invoke
11
+ action.create_action_path(action_names, $scope, $element).then (act) -> act.invoke($parse($attrs.invoke)($scope)) if $attrs.invoke?
12
12
 
13
13
  sc = $scope
14
14
  if sc.action
@@ -22,13 +22,13 @@ angular.module('Engine2')
22
22
  $http.get("api/meta").then (mresponse) -> $scope.$broadcast "bootstrap_action",
23
23
  $scope.action = new E2Actions.root(mresponse.data, $scope, null, $element, action_resource: 'api')
24
24
 
25
- .factory 'E2Actions', (E2, $http, $timeout, $e2Modal, $injector, $compile, $templateCache, $q, localStorageService, $route, $window, $rootScope, $location) ->
25
+ .factory 'E2Actions', (E2, $http, $timeout, $injector, $compile, $templateCache, $q, localStorageService, $rootScope, $location, angularLoad, $websocket, MetaCache, $stateRegistry, $urlRouter) ->
26
26
  globals = E2.globals
27
27
  action: class Action
28
28
  constructor: (response, scope, parent, element, action_info) ->
29
29
  @find_action_info = (name, raise = true) ->
30
30
  act = response.actions[name]
31
- throw "Undefined action '#{name}' for action #{@action_info().name} (under #{@parent()?.action_info().action_resource})" if raise && !act
31
+ throw "Undefined action '#{name}' for action #{@parent()?.action_info().action_resource}/#{@action_info().name}" if raise && !act
32
32
  act
33
33
 
34
34
  _.each response.actions, (act, nm) -> act.name = nm
@@ -51,11 +51,12 @@ angular.module('Engine2')
51
51
  @meta.panel.modal_action = false
52
52
  @meta.panel.footer = true unless @meta.panel.footer == false
53
53
 
54
+ @websocket_connect() if @meta.websocket
54
55
  @initialize()
55
56
 
56
57
  initialize: ->
57
58
  @process_static_meta()
58
- console.log "CREATE #{@action_info().action_resource}"
59
+ console.info "CREATE #{@action_info().action_resource}"
59
60
 
60
61
  process_static_meta: ->
61
62
  if @meta.menus
@@ -67,45 +68,22 @@ angular.module('Engine2')
67
68
  if action_info.access
68
69
  $rootScope.$broadcast "relogin", element?, create
69
70
  else
70
- $e2Modal.error("#{err.status}: #{err.data.message}", err.data.cause || err.data.message)
71
+ @globals().modal().error("#{err.status}: #{err.data.message}", err.data.cause || err.data.message)
71
72
  $q.reject(err)
72
73
 
73
- perform_invoke: (params) ->
74
- info = @action_info()
75
- get_invoke = if @meta.invokable == false then $q.when(data: (response: {})) else
76
- (params ?= {}).initial = true if @meta.panel && !@action_invoked && info.method == 'get'
77
- $http[info.method](info.action_resource, if info.method == 'post' then params else (params: params))
78
-
79
- globals.action_pending = if @meta.panel then @ else @parent()
80
-
81
- get_invoke.then (response) =>
82
- if exec = response.data.$execute
83
- @scope().$eval(exec)
84
- delete response.data.$execute
74
+ save_state: () ->
75
+ _.each @meta.state, (s) => localStorageService.set("#{@globals().application}/#{@action_info().action_resource}/#{s}", @[s])
76
+ load_state: () ->
77
+ _.each @meta.state, (s) => _.merge(@[s], localStorageService.get("#{@globals().application}/#{@action_info().action_resource}/#{s}"))
85
78
 
86
- E2.merge(@, response.data)
87
- @process_meta()
88
- (if @meta.reload_routes then $route.load_routes() else $q.when({})).then =>
89
- @arguments = _.keys(response.data)
90
- unless @meta.panel # persistent action
91
- prnt = @parent()
92
- throw "Attempted parent merge for root action: #{info.name}" unless prnt
93
- E2.merge(prnt, response.data)
94
-
95
- globals.action_pending = false
96
- if @meta.panel && !@action_invoked
97
- @action_invoked = true
98
- @panel_render()
99
- ,
100
- (err) =>
101
- globals.action_pending = false
102
- @handle_error(err, info, @element())
79
+ destroy: (e) ->
80
+ console.log "DESTROY #{@action_info().action_resource}"
103
81
 
104
82
  create_action: (name, sc, el) ->
105
83
  info = @find_action_info(name)
106
84
  info.action_resource = "#{@action_info().action_resource}/#{info.name}"
107
85
  get_meta = if !info.terminal || info.meta
108
- $http.get("#{info.action_resource}/meta", cache: true).then (response) =>
86
+ $http.get("#{info.action_resource}/meta", cache: MetaCache).then (response) =>
109
87
  if info.recheck_access
110
88
  $http.get("#{info.action_resource}/meta", params: (access: true, parent_id: @current_id())).then (aresponse) ->
111
89
  response.data.actions[k].access = v for k, v of aresponse.data
@@ -113,7 +91,7 @@ angular.module('Engine2')
113
91
  else response # $q.when ^
114
92
  else $q.when(data: (meta: {}, actions: []))
115
93
  E2A = $injector.get("E2Actions")
116
- get_meta.then (mresponse) => new (E2A[info.meta_type] ? E2A.default_action)(mresponse.data, sc, @, el, info)
94
+ get_meta.then (mresponse) => new (E2A[info.action_type] ? E2A.default_action)(mresponse.data, sc, @, el, info)
117
95
  ,
118
96
  (err) => @handle_error(err, info, el)
119
97
 
@@ -130,26 +108,44 @@ angular.module('Engine2')
130
108
  pre_invoke: ->
131
109
  post_invoke: ->
132
110
 
133
- invoke: (args) ->
134
- @pre_invoke(args)
135
- _.merge(args ?= {}, @meta.arguments) if @meta.arguments
136
- @perform_invoke(args).then =>
137
- @post_invoke(args)
111
+ invoke: (params) ->
112
+ params ?= {}
113
+ @globals().action_pending = if @meta.panel then @ else @parent()
114
+ @pre_invoke(params)
115
+ _.merge(params, @meta.arguments) if @meta.arguments
116
+
117
+ info = @action_info()
118
+ get_invoke = if @meta.invokable == false then $q.when(data: (response: {})) else
119
+ params.initial = true if @meta.panel && !@action_invoked && info.method == 'get'
120
+ $http[info.method](info.action_resource, if info.method == 'post' then params else (params: params))
121
+
122
+ get_invoke.then (response) =>
123
+ @arguments = _.keys(response.data)
124
+ E2.merge(@, response.data)
125
+ @process_meta()
126
+
127
+ promise = if @meta.panel # persistent action
128
+ if !@action_invoked
129
+ @action_invoked = true
130
+ @panel_render()
131
+ else
132
+ prnt = @parent()
133
+ throw "Attempted parent merge for root action: #{info.name}" unless prnt
134
+ E2.merge(prnt, response.data)
135
+
136
+ @post_invoke(params)
138
137
  @scope().$eval(@meta.execute) if @meta.execute
139
138
  if @meta.repeat
140
- unless @meta.destroy_repeat
141
- @scope().$on("$destroy", => delete @meta.repeat)
142
- @meta.destroy_repeat = true
143
- $timeout (=> @invoke(args)), @meta.repeat
144
- @
139
+ @scope().$on "$destroy", => @destroyed = true
140
+ $timeout (=> @invoke(params)), @meta.repeat unless @destroyed
141
+ delete @meta.repeat
145
142
 
146
- save_state: () ->
147
- _.each @meta.state, (s) => localStorageService.set("#{globals.application}/#{@action_info().action_resource}/#{s}", @[s])
148
- load_state: () ->
149
- _.each @meta.state, (s) => _.merge(@[s], localStorageService.get("#{globals.application}/#{@action_info().action_resource}/#{s}"))
150
-
151
- destroy: (e) ->
152
- console.log "DESTROY #{@action_info().action_resource}"
143
+ @globals().action_pending = false
144
+ promise
145
+ ,
146
+ (err) =>
147
+ @globals().action_pending = false
148
+ @handle_error(err, info, @element())
153
149
 
154
150
  panel_render: ->
155
151
  if @meta.panel.modal_action
@@ -161,13 +157,13 @@ angular.module('Engine2')
161
157
  @panel_shown?()
162
158
 
163
159
  else
164
- $e2Modal.show(@)
160
+ @globals().modal().show(@).then => @
165
161
  else
166
162
  @panel_scope?().$destroy()
167
163
  act = @
168
164
  act = act.parent() until act.element()
169
165
  element = act.element() # @element()
170
- is_modal = $e2Modal.is_modal() && !@element()
166
+ is_modal = @globals().modal().is_modal() && !@element()
171
167
  E2.fetch_panel(@meta.panel, is_modal).then (template) =>
172
168
  @panel_show?()
173
169
  # @panel_scope().$destroy()
@@ -190,7 +186,7 @@ angular.module('Engine2')
190
186
  panel_close: ->
191
187
  if @meta.panel.modal_action
192
188
  @modal_hide()
193
- else
189
+ else if @parent().parent()
194
190
  # @parent().panel_refresh()
195
191
  @panel_hide?()
196
192
  @panel_hidden()
@@ -201,12 +197,39 @@ angular.module('Engine2')
201
197
  panel_menu_cancel: ->
202
198
  @panel_close()
203
199
 
200
+ websocket_connect: ->
201
+ l = $location
202
+ ws_meta = @meta.websocket
203
+ ws = $websocket "ws#{l.protocol().slice(4, 5)}://#{l.host()}:#{l.port()}/#{@action_info().action_resource}", undefined, ws_meta.options
204
+ _.each @globals().ws_methods, (method) =>
205
+ ws_method_impl = @["ws_#{method}"]
206
+ ws_method_exec = ws_meta.execute?[method]
207
+ if ws_method_impl || ws_method_exec
208
+ ws_method = (evt) =>
209
+ is_message = method == 'message'
210
+ if is_message
211
+ msg = JSON.parse(evt.data)
212
+ if msg.error then @globals().modal().error("WebSocket [#{evt.origin}] - #{msg.error.method}", msg.error.exception) else
213
+ E2.merge(@, msg)
214
+ @process_meta()
215
+ else msg = evt
216
+ ws_method_impl.bind(@)(msg, ws, evt) if ws_method_impl
217
+ @scope().$eval(ws_method_exec) if ws_method_exec
218
+
219
+ ws["on#{_.capitalize(method)}"](ws_method)
220
+
221
+ @web_socket = -> ws
222
+ @scope().$on "$destroy", -> ws.close()
223
+
204
224
  root: class RootAction extends Action
205
225
  initialize: ->
206
226
  super()
207
227
  _.merge(globals, @meta)
208
228
  @meta = {}
209
229
 
230
+ invoke: (args) ->
231
+ console.warn "Root action invoked"
232
+
210
233
  default_action: class DefaultAction extends Action
211
234
  initialize: ->
212
235
  super()
@@ -217,6 +240,7 @@ angular.module('Engine2')
217
240
  super()
218
241
  @tree = actions: [name: 'api', number: 0, access: true]
219
242
  @invoke_action('models')
243
+ @invoke_action('environment')
220
244
 
221
245
  open: (stack, node, collapsed, expand) ->
222
246
  tree = @tree
@@ -253,64 +277,65 @@ angular.module('Engine2')
253
277
  has_assoc: (model) ->
254
278
  _.size(model.assoc) > 0
255
279
 
280
+ ws_message: (msg, ws, evt) ->
281
+ @event = evt
282
+
256
283
  menu: class MenuAction extends Action
257
284
  process_static_meta: ->
258
285
 
259
286
  initialize: ->
260
287
  super()
261
- $route.load_routes = =>
288
+ $stateRegistry.load_routes = (init) =>
262
289
  @invoke().then =>
263
- _.each _.keys($route.routes), (k) -> delete $route.routes[k]
264
290
  menu = @meta.menus.menu
265
- $route.routes[null] = reloadOnSearch: true, redirectTo: '/' + (menu.properties.default ? menu.entries[0].name)
291
+ _.each $stateRegistry.get(), (s) -> $stateRegistry.deregister(s.name) unless _.isEmpty(s.name)
292
+ otherwise = menu.properties.default ? menu.entries[0].name
293
+ $urlRouter.otherwise(otherwise)
266
294
  @register(menu.entries)
267
- $route.reload() # $location.path('')
268
295
  @scope().routes = menu.entries
269
296
  out = if _.size(menu.entries) == 0 then angular.element("<div></div>") else $compile(@traverse(menu.entries))(@scope())
270
297
  @element().replaceWith(out)
271
298
  @element = -> out
272
- $route.load_routes()
299
+ loc = $location.path().slice(1)
300
+ @globals().state().go(if init && !_.isEmpty($location.path()) && $stateRegistry.get(loc)? then loc else otherwise)
301
+
302
+ $stateRegistry.load_routes(true)
273
303
 
274
304
  register: (routes) ->
275
305
  _.each routes, (route) =>
276
- if route.menu then @register(route.menu.entries) else
277
- name = '/' + route.name
278
- route.href = '#' + route.name
279
- if route.bootstrap?
280
- action = if route.bootstrap == true then '' else route.bootstrap + '/'
281
- $templateCache.put(route.name + '_route_template!', "<div e2-action='' action=\"'#{action}#{route.name}'\" invoke='true'></div>")
282
-
283
- $route.routes[name] =
284
- reloadOnSearch: true
285
- templateUrl: if route.bootstrap? then route.name + '_route_template!' else route.name
286
- originalPath: name
287
- regexp: new RegExp("^#{name}$")
288
- keys: []
289
-
290
- $route.routes[name + '/'] =
291
- redirectTo: name
292
- originalPath: name + '/'
293
- regexp: new RegExp("^#{name}/$")
294
- keys: []
306
+ unless route.divider
307
+ if route.menu then @register(route.menu.entries) else
308
+ route.href = route.name
309
+ if route.bootstrap?
310
+ action = if route.bootstrap == true then '' else route.bootstrap + '/'
311
+ $templateCache.put(route.name + '_route_template!', "<div e2-action='' action=\"'#{action}#{route.name}'\" invoke='true'></div>")
312
+
313
+ $stateRegistry.register
314
+ name: route.name
315
+ templateUrl: if route.bootstrap? then route.name + '_route_template!' else route.name
316
+ url: '/' + route.name
317
+ # reloadOnSearch: true
295
318
 
296
319
  traverse: (routes) ->
297
- menu_tmpl = _.template("<li><a href='{{href}}'>{{icon}}{{aicon}} {{loc}}</a></li>")
298
- menu_sub_tmpl = _.template("<li e2-dropdown='{{dropdown}}' data-animation='{{animation}}'><a href='javascript://'>{{icon}}{{aicon}} {{loc}}<span class='caret'></span></a></li>")
320
+ menu_tmpl = _.template("<li {{show}} {{hide}} ui-sref-active='active'><a {{href}}>{{icon}} {{loc}}</a></li>")
321
+ menu_sub_tmpl = _.template("<li {{show}} {{hide}} e2-dropdown='{{dropdown}}' href-attr='ui-sref' data-animation='{{animation}}'><a href='javascript://'>{{icon}} {{loc}}<span class='caret'></span></a></li>")
299
322
  animation = @meta.menus.menu.properties.animation
300
323
  out = routes.map (route, i) ->
301
324
  if route.menu
302
325
  menu_sub_tmpl
303
326
  dropdown: "routes[#{i}].menu.entries"
304
327
  animation: animation
305
- icon: route.menu.icon && E2.icon(route.menu.icon) || ""
306
- aicon: route.menu.aicon && E2.aicon(route.menu.aicon) || ""
307
328
  loc: route.menu.loc
329
+ show: route.show && "ng-show=\"#{route.show}\"" || ''
330
+ hide: route.hide && "ng-hide=\"#{route.hide}\"" || ''
331
+ icon: route.menu.icon && E2.icon(route.menu.icon) || ""
308
332
  else
309
333
  menu_tmpl
310
- href: route.href
334
+ href: "ui-sref='#{route.name}'"
311
335
  loc: route.loc
336
+ show: route.show && "ng-show=\"#{route.show}\"" || ''
337
+ hide: route.hide && "ng-hide=\"#{route.hide}\"" || ''
312
338
  icon: route.icon && E2.icon(route.icon) || ''
313
- aicon: route.aicon && E2.aicon(route.aicon) || ''
314
339
  out.join('')
315
340
 
316
341
  list: class ListAction extends Action
@@ -322,7 +347,6 @@ angular.module('Engine2')
322
347
 
323
348
  delete @query.order unless @meta.info[@query.order]?.sort # _.includes(@meta.fields, @query.order)
324
349
  _.each @query.search, ((sv, sn) => delete @query.search[sn] unless _.includes(@meta.search_fields, sn))
325
- # $window.addEventListener 'beforeunload', (e, v) => @save_state()
326
350
 
327
351
  destroy: ->
328
352
  @save_state()
@@ -351,7 +375,7 @@ angular.module('Engine2')
351
375
  @scope().$broadcast 'render_table'
352
376
 
353
377
  menu_show_meta: ->
354
- $e2Modal.show
378
+ @globals().modal().show
355
379
  the_meta: @meta
356
380
  meta: panel: (panel_template: "close_m", template_string: "<pre>{{action.the_meta | json}}</pre>", title: "Meta", class: "modal-huge", backdrop: true, footer: true)
357
381
 
@@ -469,7 +493,6 @@ angular.module('Engine2')
469
493
  @panel_shown()
470
494
 
471
495
  @["panel_menu_#{@default_action_name}"] = -> @panel_menu_default_action()
472
- @scope().$on "return_pressed", (e) => @panel_menu_default_action()
473
496
 
474
497
  post_invoke: (args) ->
475
498
  super()
@@ -505,9 +528,8 @@ angular.module('Engine2')
505
528
  @alert = @errors if (!field || !@meta.info[field] || @meta.info[field].hidden) # ?
506
529
  $timeout => @scope().$broadcast("focus_field", field)
507
530
  #e.scope.$eval(meta.execute) if meta.execute # ?
508
- dfd.reject(@errors)
531
+ dfd.resolve()
509
532
  else
510
- @panel_close()
511
533
  dfd.resolve(@record) # $q.when(true) ?
512
534
  dfd.promise
513
535
 
@@ -533,30 +555,31 @@ angular.module('Engine2')
533
555
  act.meta.info.name.disabled = true
534
556
  act.dont_reload_routes = !reload_routes # true
535
557
  else
536
- @invoke().then => @set_access(true, true)
558
+ @invoke().then => @set_access(true, true, @user)
537
559
 
538
- set_access: (login, load_routes) ->
539
- @find_action_info('logout_form').access = login
540
- @find_action_info('inspect_modal').access = login
541
- @find_action_info('login_form').access = !login
542
- $route.load_routes() if load_routes
560
+ @scope().$on "set_access", (evt, login, load_routes, user) => @set_access(login, load_routes, user)
561
+
562
+ set_access: (login, load_routes, user) ->
563
+ if user || !login
564
+ @user = user
565
+ @find_action_info('logout_form').access = login
566
+ @find_action_info('inspect_modal').access = login
567
+ @find_action_info('login_form').access = !login
568
+ $stateRegistry.load_routes() if load_routes
543
569
 
544
570
  login_form: class LoginFormAction extends FormBaseAction
545
571
  panel_menu_default_action: ->
546
572
  super().then =>
547
- @parent().user = @user
548
- @parent().set_access(true, !@dont_reload_routes)
573
+ $rootScope.$broadcast "set_access", true, !@dont_reload_routes, @user
549
574
 
550
575
  logout_form: class LogoutForm extends Action
551
576
  panel_menu_logout: ->
552
577
  @invoke_action('logout').then =>
553
- @parent().user = null
554
- @parent().set_access(false, true)
578
+ $rootScope.$broadcast "set_access", false, true, null
555
579
  @panel_close()
580
+ MetaCache.removeAll()
556
581
 
557
582
  form: class FormAction extends FormBaseAction
558
- panel_menu_default_action: ->
559
- super().then => @parent().invoke()
560
583
 
561
584
  create: class CreateAction extends FormAction
562
585
  invoke: (args) ->
@@ -578,10 +601,7 @@ angular.module('Engine2')
578
601
  confirm: class ConfirmAction extends Action
579
602
  panel_menu_approve: ->
580
603
  @initial_arguments ?= @arguments
581
- @invoke_action(@default_action_name, _.pick(@, @initial_arguments)).then (act) =>
582
- unless @errors
583
- @parent().invoke()
584
- @panel_close()
604
+ @invoke_action(@default_action_name, _.pick(@, @initial_arguments))
585
605
 
586
606
  decode_action: class DecodeAction extends Action
587
607
  initialize: ->
@@ -606,8 +626,7 @@ angular.module('Engine2')
606
626
  @parentp().search_field_change?(@decode_field)
607
627
 
608
628
  decode_description: (entry) ->
609
- fields = @meta.decode_fields ? @meta.fields
610
- fields.map((f) => E2.render_field(entry, f, @meta)).join(@meta.separator)
629
+ @meta.decode_fields.map((f) => E2.render_field(entry, f, @meta)).join(@meta.separator)
611
630
 
612
631
  parentp: ->
613
632
  @parent().parent()
@@ -675,7 +694,7 @@ angular.module('Engine2')
675
694
  else
676
695
  decode_descriptions = (recs) => @decode = recs.map((fields) => @decode_description(fields)).join(' | ')
677
696
  recs = recs.map (r) => if _.isArray(r) then E2.from_id(r, @meta) else r
678
- if _(recs).every((r) => _(@meta.fields).every((f) -> r[f]?)) then decode_descriptions(recs) else
697
+ if _(recs).every((r) => _(@meta.fields).every((f) -> r[f]?)) && !@meta.dynamic_meta then decode_descriptions(recs) else
679
698
  @invoke(ids: [recs.map((r) => @meta.primary_fields.map (k) -> r[k])]).then => decode_descriptions(@entries)
680
699
 
681
700
  open: ->
@@ -743,8 +762,9 @@ angular.module('Engine2')
743
762
  @query.parent_id = @parent().current_id()
744
763
 
745
764
  # link_list: implicit
746
- item_menu_confirm_unlink: (index) ->
747
- @invoke_action('confirm_unlink', id: E2.id_for(@entries[index], @meta), parent_id: @query.parent_id)
765
+ item_menu_confirm_unlink: (args) ->
766
+ args.parent_id = @query.parent_id
767
+ @item_menu_confirm_unlink_super(args)
748
768
 
749
769
  star_to_many_bulk_unlink: class StarToManyBulkUnlinkAction extends Action
750
770
  invoke: ->
@@ -762,26 +782,63 @@ angular.module('Engine2')
762
782
  panel_menu_link: ->
763
783
  selection = _.keys(@selection)
764
784
  if selection.length > 0
765
- @invoke_action('link', parent_id: @query.parent_id, ids: selection).then (act) =>
766
- unless @errors
767
- @parent().invoke()
768
- @panel_close()
785
+ @invoke_action('link', parent_id: @query.parent_id, ids: selection)
769
786
 
770
787
  star_to_many_field: class StarToManyField extends ListAction
771
788
  initialize: ->
772
789
  super()
773
790
  @query.parent_id = E2.id_for(@parent().record, @parent().meta)
774
- links = @parent().record[@scope().$parent.f]
775
- @links = links ? (linked: [], unlinked: [])
791
+ @changes = (@parent().record[@scope().$parent.f] ?= (link: [], unlink: [], create: [], modify: [], delete: []))
776
792
  @invoke()
777
793
 
778
794
  invoke: ->
779
- @query.unlinked = [@links.unlinked]
780
- @query.linked = [@links.linked]
795
+ @query.changes = @changes
781
796
  super()
782
797
 
783
- sync_record: ->
784
- @parent().record[@scope().$parent.f] = @links
798
+ current_entry_is: (mode) ->
799
+ key = E2.id_for(@current_entry(), @meta)
800
+ _.find(@changes[mode], (e) => E2.id_for(e, @meta) == key)
801
+
802
+ star_to_many_field_view: class StarToManyFieldView extends ViewAction
803
+ invoke: (args) ->
804
+ if entry = @parent().current_entry_is('create') ? @parent().current_entry_is('modify')
805
+ @meta.invokable = false
806
+ @record = entry
807
+ super(args)
808
+
809
+ star_to_many_field_modify: class StarToManyFieldModifyAction extends ModifyAction
810
+ invoke: (args) ->
811
+ if entry = @parent().current_entry_is('create') ? @parent().current_entry_is('modify')
812
+ @meta.invokable = false
813
+ @record = entry
814
+ super(args)
815
+
816
+ star_to_many_field_approve: class StarToManyFieldApprove extends Action
817
+ post_invoke: (args) ->
818
+ super(args)
819
+ unless @errors
820
+ pparent = @parent().parent()
821
+ if @parent() instanceof StarToManyFieldModifyAction
822
+ if entry = pparent.current_entry_is('create') ? pparent.current_entry_is('modify')
823
+ _.assign(entry, @parent().record)
824
+ else
825
+ pparent.changes.modify.push @parent().record
826
+ else # CreateAction
827
+ _(@parent().meta.primary_fields).each (k) => @parent().record[k] = E2.uuid(5)
828
+ pparent.changes.create.push @parent().record
829
+
830
+ star_to_many_field_delete: class StarToManyFieldDelete extends Action
831
+ invoke: (args) ->
832
+ pparent = @parent().parent()
833
+ if entry = pparent.current_entry_is('create')
834
+ _.remove(pparent.changes.create, entry)
835
+ else if entry = pparent.current_entry_is('modify')
836
+ _.remove(pparent.changes.modify, entry)
837
+ pparent.changes.delete.push args.id
838
+ else
839
+ pparent.changes.delete.push args.id
840
+ @meta.invokable = false
841
+ super(args)
785
842
 
786
843
  star_to_many_field_link_list: class StarToManyFieldLinkList extends ListAction
787
844
  initialize: ->
@@ -791,57 +848,50 @@ angular.module('Engine2')
791
848
  @selection = {}
792
849
 
793
850
  invoke: ->
794
- @query.unlinked = [@parent().links.unlinked]
795
- @query.linked = [@parent().links.linked]
851
+ @query.changes = @parent().changes
796
852
  super()
797
853
 
798
854
  panel_menu_link: ->
799
855
  if @selected_size() > 0
800
856
  _.each @selection, (v, k) =>
801
857
  id = k
802
- if _.includes(@parent().links.unlinked, id) then _.pull(@parent().links.unlinked, id) else @parent().links.linked.push id
858
+ if _.includes(@parent().changes.unlink, id) then _.pull(@parent().changes.unlink, id) else @parent().changes.link.push id
803
859
  @parent().invoke()
804
- @parent().sync_record()
805
860
  @panel_close()
806
861
 
807
862
  star_to_many_field_unlink: class StarToManyFieldUnlink extends Action
808
863
  invoke: (args) ->
809
864
  id = args.id
810
865
  pparent = @parent().parent()
811
- if _.includes(pparent.links.linked, id) then _.pull(pparent.links.linked, id) else pparent.links.unlinked.push id
812
- pparent.sync_record()
866
+ if _.includes(pparent.changes.link, id) then _.pull(pparent.changes.link, id) else pparent.changes.unlink.push id
867
+ @meta.invokable = false
868
+ super(args)
813
869
 
814
870
  file_store: class FileStoreAction extends Action
815
871
  initialize: ->
816
872
  super()
817
873
  @progress = 0
818
874
  id = E2.id_for(@parent().record, @parent().meta)
819
- if id.length > 0
820
- @invoke(owner: id).then => @sync_record()
821
- else
822
- @files = []
823
- @sync_record()
824
-
825
- sync_record: ->
826
- @parent().record[@scope().f] = @files
875
+ files = @parent().record[@scope().f]
876
+ @invoke(owner: id).then =>
877
+ @parent().record[@scope().f] = if files? then files else @files
878
+ delete @files
827
879
 
828
880
  select: (files) ->
829
881
  _.each files, (file) =>
830
882
  upload = $injector.get('Upload').upload url: "#{@action_info().action_resource}/upload", file: file
831
883
  upload.progress (e) =>
832
- globals.action_pending = false
884
+ @globals().action_pending = false
833
885
  @progress = parseInt(100.0 * e.loaded / e.total)
834
886
  upload.success (data, status, headers, config) =>
835
- @files.push mime: file.type, name: file.name, rackname: data.rackname, id: data.id
887
+ @parent().record[@scope().f].push mime: file.type, name: file.name, rackname: data.rackname, id: data.id, new: true
836
888
  @message = "Wysłano, #{file.name}"
837
- globals.action_pending = false
838
- @sync_record()
889
+ @globals().action_pending = false
839
890
 
840
891
  delete_file: (file) ->
841
892
  @scope().$broadcast 'confirm_delete',
842
893
  confirm: =>
843
- @sync_record()
844
- file.deleted = true
894
+ if file.new then _.pull(@parent().record[@scope().f], file) else file.deleted = true
845
895
  @scope().$broadcast 'confirm_delete_close'
846
896
 
847
897
  show_file: (file) ->