engine2 1.0.3 → 1.0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (133) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +3 -117
  3. data/{views → app}/app.coffee +0 -0
  4. data/{public/css → app}/app.css +203 -196
  5. data/{views → app}/engine2.coffee +111 -60
  6. data/{views → app}/engine2actions.coffee +47 -28
  7. data/bower.json +13 -0
  8. data/conf/message.yaml +2 -1
  9. data/conf/message_pl.yaml +2 -1
  10. data/config.coffee +62 -0
  11. data/engine2.gemspec +2 -5
  12. data/lib/engine2.rb +1 -1
  13. data/lib/engine2/action.rb +9 -24
  14. data/lib/engine2/core.rb +9 -8
  15. data/lib/engine2/handler.rb +1 -5
  16. data/lib/engine2/meta.rb +61 -24
  17. data/lib/engine2/meta/array_meta.rb +82 -0
  18. data/lib/engine2/meta/decode_meta.rb +1 -1
  19. data/lib/engine2/meta/infra_meta.rb +21 -26
  20. data/lib/engine2/meta/list_meta.rb +2 -3
  21. data/lib/engine2/model.rb +5 -5
  22. data/lib/engine2/pre_bootstrap.rb +9 -1
  23. data/lib/engine2/scheme.rb +4 -0
  24. data/lib/engine2/type_info.rb +8 -1
  25. data/lib/engine2/version.rb +1 -1
  26. data/package.json +38 -0
  27. data/public/img/ajax-loader.gif +0 -0
  28. data/views/fields/blob.slim +4 -5
  29. data/views/fields/bs_select.slim +2 -2
  30. data/views/fields/bsselect_picker.slim +1 -2
  31. data/views/fields/bsselect_picker_opt.slim +1 -2
  32. data/views/fields/checkbox.slim +1 -1
  33. data/views/fields/checkbox_buttons.slim +1 -1
  34. data/views/fields/checkbox_buttons_opt.slim +1 -1
  35. data/views/fields/currency.slim +2 -2
  36. data/views/fields/date.slim +0 -1
  37. data/views/fields/date_range.slim +0 -1
  38. data/views/fields/date_time.slim +0 -1
  39. data/views/fields/datetime.slim +0 -2
  40. data/views/fields/decimal.slim +0 -1
  41. data/views/fields/decimal_date.slim +0 -1
  42. data/views/fields/decimal_time.slim +0 -1
  43. data/views/fields/email.slim +1 -2
  44. data/views/fields/file_store.slim +1 -1
  45. data/views/fields/input_text.slim +1 -2
  46. data/views/fields/integer.slim +1 -1
  47. data/views/fields/list_bsselect.slim +1 -2
  48. data/views/fields/list_bsselect_opt.slim +2 -3
  49. data/views/fields/list_buttons.slim +1 -1
  50. data/views/fields/list_buttons_opt.slim +1 -1
  51. data/views/fields/list_select.slim +1 -2
  52. data/views/fields/list_select_opt.slim +2 -3
  53. data/views/fields/password.slim +1 -2
  54. data/views/fields/radio_checkbox.slim +1 -1
  55. data/views/fields/scaffold.slim +1 -1
  56. data/views/fields/scaffold_picker.slim +1 -2
  57. data/views/fields/select_picker.slim +1 -2
  58. data/views/fields/select_picker_opt.slim +1 -2
  59. data/views/fields/text_area.slim +0 -1
  60. data/views/fields/time.slim +0 -1
  61. data/views/fields/typeahead_picker.slim +1 -2
  62. data/views/index.slim +4 -8
  63. data/views/scaffold/fields.slim +4 -4
  64. data/views/scaffold/form.slim +1 -7
  65. data/views/scaffold/form_collapse.slim +19 -0
  66. data/views/scaffold/form_tabs.slim +9 -0
  67. data/views/scaffold/list.slim +1 -12
  68. data/views/scaffold/search.slim +2 -9
  69. data/views/scaffold/search_collapse.slim +26 -0
  70. data/views/scaffold/search_tabs.slim +15 -0
  71. data/views/scaffold/view.slim +5 -15
  72. data/views/scaffold/view_collapse.slim +22 -0
  73. data/views/scaffold/view_tabs.slim +11 -0
  74. data/views/search_fields/bsmselect_picker.slim +1 -2
  75. data/views/search_fields/bsselect_picker.slim +1 -2
  76. data/views/search_fields/checkbox.slim +3 -3
  77. data/views/search_fields/checkbox2.slim +5 -5
  78. data/views/search_fields/checkbox_buttons.slim +2 -2
  79. data/views/search_fields/date_range.slim +0 -2
  80. data/views/search_fields/decimal_date_range.slim +5 -5
  81. data/views/search_fields/input_text.slim +2 -2
  82. data/views/search_fields/integer.slim +1 -1
  83. data/views/search_fields/integer_range.slim +2 -2
  84. data/views/search_fields/list_bsmselect.slim +1 -1
  85. data/views/search_fields/list_bsselect.slim +0 -1
  86. data/views/search_fields/list_buttons.slim +2 -2
  87. data/views/search_fields/list_select.slim +1 -2
  88. data/views/search_fields/scaffold_picker.slim +1 -2
  89. data/views/search_fields/select_picker.slim +1 -2
  90. data/views/search_fields/typeahead_picker.slim +1 -2
  91. metadata +29 -103
  92. data/public/assets/javascripts.js +0 -13
  93. data/public/assets/styles.css +0 -4
  94. data/public/css/angular-motion.css +0 -1022
  95. data/public/css/angular-ui-tree.min.css +0 -1
  96. data/public/css/bootstrap-additions.css +0 -1560
  97. data/public/css/bootstrap.min.css +0 -11
  98. data/public/css/font-awesome.min.css +0 -4
  99. data/public/fonts/FontAwesome.otf +0 -0
  100. data/public/fonts/fontawesome-webfont.eot +0 -0
  101. data/public/fonts/fontawesome-webfont.svg +0 -655
  102. data/public/fonts/fontawesome-webfont.ttf +0 -0
  103. data/public/fonts/fontawesome-webfont.woff +0 -0
  104. data/public/fonts/fontawesome-webfont.woff2 +0 -0
  105. data/public/fonts/glyphicons-halflings-regular.eot +0 -0
  106. data/public/fonts/glyphicons-halflings-regular.svg +0 -288
  107. data/public/fonts/glyphicons-halflings-regular.ttf +0 -0
  108. data/public/fonts/glyphicons-halflings-regular.woff +0 -0
  109. data/public/fonts/glyphicons-halflings-regular.woff2 +0 -0
  110. data/public/images/file.png +0 -0
  111. data/public/images/folder-closed.png +0 -0
  112. data/public/images/folder.png +0 -0
  113. data/public/images/node-closed-2.png +0 -0
  114. data/public/images/node-closed-light.png +0 -0
  115. data/public/images/node-closed.png +0 -0
  116. data/public/images/node-opened-2.png +0 -0
  117. data/public/images/node-opened-light.png +0 -0
  118. data/public/images/node-opened.png +0 -0
  119. data/public/img/ajax-loader-light.gif +0 -0
  120. data/public/js/angular-animate.js +0 -4147
  121. data/public/js/angular-cookies.js +0 -322
  122. data/public/js/angular-local-storage.js +0 -455
  123. data/public/js/angular-route.js +0 -1025
  124. data/public/js/angular-sanitize.js +0 -717
  125. data/public/js/angular-strap.js +0 -4339
  126. data/public/js/angular-strap.tpl.js +0 -43
  127. data/public/js/angular-ui-tree.js +0 -1569
  128. data/public/js/angular.js +0 -30868
  129. data/public/js/i18n/angular-locale_pl.js +0 -115
  130. data/public/js/lodash.custom.min.js +0 -99
  131. data/public/js/ng-file-upload-shim.min.js +0 -2
  132. data/public/js/ng-file-upload.min.js +0 -3
  133. data/views/engine2templates.coffee +0 -0
@@ -1,20 +1,15 @@
1
1
  'use strict'
2
+ require 'angular-route'
3
+ require 'angular-sanitize'
4
+ require 'angular-animate'
5
+ require 'angular-cookies'
6
+ require 'angular-local-storage'
7
+ require 'angular-ui-tree'
8
+ require 'ng-file-upload'
9
+
2
10
  _.templateSettings.interpolate = /{{([\s\S]+?)}}/g;
3
11
 
4
12
  angular.module('Engine2', ['ngRoute', 'ngSanitize', 'ngAnimate', 'ngCookies', 'mgcrea.ngStrap', 'ngFileUpload', 'ui.tree', 'LocalStorageModule']) # 'draggabilly'
5
- .factory 'E2Snippets', ->
6
- icon = (name) -> "<span class='glyphicon glyphicon-#{name}'></span>"
7
- aicon = (name) -> "<i class='fa fa-#{name}'></i>"
8
- ng_class_names = ['active', 'enabled', 'disabled']
9
- icon: icon
10
- aicon: aicon
11
- boolean_true_value: icon('check')
12
- boolean_false_value: icon('unchecked')
13
- make_ng_class: (o) ->
14
- out = []
15
- _.each ng_class_names, (e) -> out.push(if e == 'enabled' then "'disabled': !(#{o[e]})" else "'#{e}': #{o[e]}") if o[e]?
16
- if out.length > 0 then "ng-class=\"{#{out.join(',')}}\"" else ""
17
-
18
13
  .config ($httpProvider, $routeProvider, $compileProvider, localStorageServiceProvider, $logProvider) ->
19
14
  loaderOn = -> angular.element(document.querySelectorAll('.loader')).eq(-1).css("visibility", 'visible')
20
15
  $httpProvider.interceptors.push 'e2HttpInterceptor'
@@ -51,7 +46,23 @@ angular.module('Engine2', ['ngRoute', 'ngSanitize', 'ngAnimate', 'ngCookies', 'm
51
46
  $injector.get('$e2Modal').error("#{E2Snippets.icon('bell')} #{response.status}: #{message}", cause)
52
47
  $q.reject(response)
53
48
 
54
- .factory 'E2', ($templateCache, $http, E2Snippets, $e2Modal, $q, $injector, e2HttpInterceptor, $route, $dateFormatter) ->
49
+ .factory 'E2Snippets', ->
50
+ icon = (name) -> "<span class='glyphicon glyphicon-#{name}'></span>"
51
+ aicon = (name) -> "<i class='fa fa-#{name}'></i>"
52
+ ng_class_names = ['active', 'enabled', 'disabled']
53
+ icon: icon
54
+ aicon: aicon
55
+ boolean_true_value: icon('check')
56
+ boolean_false_value: icon('unchecked')
57
+ make_ng_class: (o) ->
58
+ out = []
59
+ _.each ng_class_names, (e) -> out.push(if e == 'enabled' then "'disabled': !(#{o[e]})" else "'#{e}': #{o[e]}") if o[e]?
60
+ _.each(o.class, (v, k) -> out.push "#{k}: #{v}") if o.class?
61
+ if out.length > 0 then "ng-class=\"{#{out.join(',')}}\"" else ""
62
+
63
+ .factory 'E2', ($templateCache, $http, E2Snippets, $e2Modal, $q, $injector, e2HttpInterceptor, $route, $dateFormatter, $parse) ->
64
+ globals: {}
65
+
55
66
  compact: (o) ->
56
67
  _.each o, (v, k) =>
57
68
  if (v == null || (_.isString(v) && !v)) || (!_.isDate(v) && _.isObject(v) && @compact(v) && _.isEmpty(v))
@@ -66,6 +77,7 @@ angular.module('Engine2', ['ngRoute', 'ngSanitize', 'ngAnimate', 'ngCookies', 'm
66
77
  else
67
78
  # delete o[k]
68
79
  o[k] = null
80
+
69
81
  merge: (dst, src) ->
70
82
  for k, v of src
71
83
  if _.isObject(v) && !_.isArray(v)
@@ -80,8 +92,8 @@ angular.module('Engine2', ['ngRoute', 'ngSanitize', 'ngAnimate', 'ngCookies', 'm
80
92
  transpose: (a) ->
81
93
  _.keys(a[0]).map((c) -> a.map (r) -> r[c])
82
94
 
83
- join_keys: (keys) -> keys.join('|')
84
- split_keys: (key) -> key.split('|')
95
+ join_keys: (keys) -> keys.join(@globals.key_separator)
96
+ split_keys: (key) -> key.split(@globals.key_separator)
85
97
  id_for: (rec, meta) -> @join_keys(meta.primary_fields.map((e) -> rec[e]))
86
98
  from_id: (id, meta) -> _.zipObject(meta.primary_fields, id) # _.zip(meta.primary_fields, id).reduce(((rec, [k, v]) -> rec[k] = v; rec), {})
87
99
 
@@ -121,13 +133,15 @@ angular.module('Engine2', ['ngRoute', 'ngSanitize', 'ngAnimate', 'ngCookies', 'm
121
133
  m.click = fun_invoke
122
134
 
123
135
  if click
124
- action[fun_name] = (args...) ->
125
- processor.arg_fun(action, args...)
136
+ action[fun_name] = (arg) ->
137
+ processor.arg_fun(action, arg)
126
138
  action.scope().$eval(click)
127
139
  else
128
- action[fun_name] ?= (args...) ->
129
- processor.arg_fun(action, args...)
130
- action.invoke_action(m.name, processor.arg_ret(action))
140
+ action[fun_name] ?= (arg) ->
141
+ processor.arg_fun(action, arg)
142
+ args = processor.arg_ret(action)
143
+ _.merge(args, $parse(m.arguments)(action.scope())) if m.arguments?
144
+ action.invoke_action(m.name, args)
131
145
 
132
146
  if action.find_action_info(m.name, false)?
133
147
  show = if m.show then " && " + m.show else ""
@@ -136,17 +150,16 @@ angular.module('Engine2', ['ngRoute', 'ngSanitize', 'ngAnimate', 'ngCookies', 'm
136
150
  menu_processors:
137
151
  menu:
138
152
  arg_name: ''
139
- arg_fun: (action) -> undefined
140
- arg_ret: (action) -> undefined
153
+ arg_fun: (action) ->
154
+ arg_ret: (action) -> {}
141
155
  panel_menu:
142
156
  arg_name: ''
143
- arg_fun: (action) -> undefined
144
- arg_ret: (action) -> undefined
157
+ arg_fun: (action) ->
158
+ arg_ret: (action) -> {}
145
159
  item_menu:
146
160
  arg_name: '$index'
147
- arg_ret: (action) -> id: action.current_id
148
- arg_fun: (action, index) ->
149
- action.current_id = $injector.get('E2').id_for(action.entries[index], action.meta)
161
+ arg_fun: (action, index) -> action.current_index = index
162
+ arg_ret: (action) -> id: action.current_id()
150
163
 
151
164
  renderers:
152
165
  boolean: (value, render) =>
@@ -180,7 +193,8 @@ angular.module('Engine2', ['ngRoute', 'ngSanitize', 'ngAnimate', 'ngCookies', 'm
180
193
  if f_info? && type = f_info.type
181
194
  @renderers[type](value, f_info.render)
182
195
  else
183
- (value + "").replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;")
196
+ if f_info?.escape == false then value else
197
+ (value + "").replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;")
184
198
  else
185
199
  value
186
200
 
@@ -200,7 +214,7 @@ angular.module('Engine2', ['ngRoute', 'ngSanitize', 'ngAnimate', 'ngCookies', 'm
200
214
  constructor: () ->
201
215
  backdrop_z_index: (num, index) -> angular.element(document.querySelectorAll('.modal-backdrop')).eq(num).css('z-index', index)
202
216
  modal_num: (num) -> angular.element(document.querySelectorAll('.modal')).eq(num)
203
- backdrop: -> 'static'
217
+ backdrop: (bdr) -> bdr ? 'static'
204
218
  show_before: ->
205
219
  @z_index = MManager.Z_INDEX + MManager.index * 2
206
220
  @modal.css('z-index', @z_index + 1)
@@ -218,7 +232,7 @@ angular.module('Engine2', ['ngRoute', 'ngSanitize', 'ngAnimate', 'ngCookies', 'm
218
232
  constructor: () ->
219
233
  super()
220
234
  @threshold = 2
221
- backdrop: -> if MManager.index > @threshold then false else super()
235
+ backdrop: (bdr) -> if MManager.index > @threshold then false else super(bdr)
222
236
  show_before: ->
223
237
  super()
224
238
  if MManager.index > @threshold
@@ -234,7 +248,7 @@ angular.module('Engine2', ['ngRoute', 'ngSanitize', 'ngAnimate', 'ngCookies', 'm
234
248
  @modal_num((MManager.index - 1) - @threshold).css('display', 'block')
235
249
 
236
250
  class SingleBackdropMManager extends MManager
237
- backdrop: -> if MManager.index > 0 then false else super()
251
+ backdrop: (bdr) -> if MManager.index > 0 then false else super(bdr)
238
252
  show_before: ->
239
253
  super()
240
254
  @backdrop_z_index(0, @z_index)
@@ -253,33 +267,38 @@ angular.module('Engine2', ['ngRoute', 'ngSanitize', 'ngAnimate', 'ngCookies', 'm
253
267
  e.stopPropagation()
254
268
  manager.modal = m.$element
255
269
  manager.backdrop = m.$backdrop
256
- throw "Modal has element" if scope.action.element?()
257
- scope.action.element = -> m.$element
258
- scope.action.panel_show?()
270
+ throw "Modal has element" if action.element?()
271
+ action.element = -> m.$element
272
+ action.panel_show?()
259
273
  manager.show_before()
260
274
  MManager.index++
261
275
 
262
276
  scope.$on 'modal.show', (e, m) ->
263
277
  e.stopPropagation()
264
278
  manager.show()
265
- scope.action.panel_shown?()
279
+ action.panel_shown?()
266
280
 
267
281
  scope.$on 'modal.hide.before', (e) ->
268
282
  e.stopPropagation()
269
283
  MManager.index--
270
284
  manager.hide_before()
271
- scope.action.panel_hide?()
285
+ action.panel_hide?()
272
286
 
273
287
  scope.$on 'modal.hide', (e) ->
274
288
  e.stopPropagation()
275
289
  manager.hide()
276
- scope.action.panel_hidden?()
290
+ action.panel_hidden?()
277
291
  scope.$destroy()
278
292
 
279
- $injector.get('E2').fetch_panel(scope.action.meta.panel, true).then (template) ->
280
- # template = "<div class='modal' ng-class='action.meta.panel.class'>#{template}</div>"
281
- modal = $modal(scope: scope, template: template, backdrop: manager.backdrop(), animation: 'am-fade', show: false)
282
- scope.action.modal_hide = -> modal.$scope.$hide()
293
+ $injector.get('E2').fetch_panel(action.meta.panel, true).then (template) ->
294
+ modal = $modal
295
+ scope: scope
296
+ show: false
297
+ template: template
298
+ backdrop: manager.backdrop(action.meta.panel.backdrop)
299
+ animation: action.meta.panel.animation ? 'am-fade'
300
+
301
+ action.modal_hide = -> modal.$scope.$hide()
283
302
  modal.$promise.then ->
284
303
  modal.show()
285
304
  modal
@@ -385,31 +404,54 @@ angular.module('Engine2', ['ngRoute', 'ngSanitize', 'ngAnimate', 'ngCookies', 'm
385
404
  elem.after($compile(body)(scope))
386
405
 
387
406
  .directive 'e2TableBody', ($parse, $compile) ->
407
+ table_tmpl = _.template("<thead><tr>{{thead}}</tr></thead><tbody>{{tbody}}</tbody>")
388
408
  scope: false
389
409
  restrict: 'A'
390
410
  link: (scope, elem, attrs) ->
391
411
  scope.$on 'render_table', (a, ev) ->
392
412
  # ev.stopPropagation()
393
- meta = scope.action.meta
394
- selection = scope.action.selection
395
- out = ''
396
- _.each scope.action.entries, (e, i) ->
397
- out += if selection then "<tr ng-class='action.selected_class(#{i})' class='tr_hover' ng-click='action.select(#{i}, $event)'>" else
413
+ action = scope.action
414
+ meta = action.meta
415
+ position = meta.menus.item_menu.properties.position ? 0
416
+ right_style = if position >= meta.fields.length then "style=\"text-align: right\"" else ""
417
+
418
+ thead = ""
419
+ fields = meta.fields.slice()
420
+ fields.splice(position, 0, null)
421
+ _.each fields, (f) ->
422
+ if f
423
+ info = meta.info[f]
424
+ thead += "<th>"
425
+ title = if info.title then "title=\"#{info.title}\"" else ""
426
+ if info.sort
427
+ thead += "<a ng-click=\"action.order('#{f}')\" #{title}><strong>#{info.loc}</strong></a>"
428
+ if action.ui.order == f
429
+ cls = if action.ui.asc then "glyphicon-chevron-up" else "glyphicon-chevron-down"
430
+ thead += " <span class=\"glyphicon #{cls}\"></span>"
431
+ else
432
+ thead += "<span #{title}>#{info.loc}</span>"
433
+ thead += "</th>"
434
+ else
435
+ thead += "<th class=\"#{meta.menus.menu.properties.class || ''}\" #{right_style}><div e2-button-set=\"action.meta.menus.menu\"></div></th>"
436
+
437
+ tbody = ""
438
+ _.each action.entries, (e, i) ->
439
+ tbody += if action.selection then "<tr ng-class=\"action.selected_class(#{i})\" class=\"tr_hover\" ng-click=\"action.select(#{i}, $event)\">" else
398
440
  row_cls = e.$row_info?.class
399
441
  if row_cls then "<tr class=\"#{row_cls}\">" else "<tr>"
400
- out += "<td>"
401
- out += "<div e2-button-set='action.meta.menus.item_menu' index='#{i}'></div>" if meta.config.show_item_menu
402
- out += "</td>"
403
- _.each meta.fields, (f) ->
404
- out += if col_cls = meta.info[f].column_class then "<td class='#{col_cls}'>" else "<td>"
405
- out += scope.action.list_cell(e, f) ? ''
406
- out += "</td>"
407
- out += "</tr>"
442
+ _.each fields, (f) ->
443
+ if f
444
+ tbody += if col_cls = meta.info[f].column_class then "<td class=\"#{col_cls}\">" else "<td>"
445
+ tbody += action.list_cell(e, f) ? ''
446
+ tbody += "</td>"
447
+ else
448
+ tbody += "<td #{right_style}><div e2-button-set=\"action.meta.menus.item_menu\" index=\"#{i}\"></div></td>"
449
+ tbody += "</tr>"
408
450
 
409
451
  elem.empty()
410
- elem.append($compile(out)(scope)) unless out.length == 0 # leak ?
452
+ elem.append($compile(table_tmpl thead: thead, tbody: tbody)(scope))
411
453
 
412
- .directive 'e2DropDown', ($parse, $dropdown, $timeout, E2Snippets) ->
454
+ .directive 'e2Dropdown', ($parse, $dropdown, $timeout, E2Snippets) ->
413
455
  event_num = 0
414
456
  dropdown_sub_tmpl = _.template("<li class='dropdown-submenu'><a href=''> {{icon}}{{aicon}} {{loc}}</a>{{sub}}</li>")
415
457
  dropdown_tmpl = _.template("<li {{clazz}} {{show}} {{hide}}> <a href='{{href}}' {{click}}> {{icon}}{{aicon}} {{loc}}</a></li>")
@@ -446,7 +488,8 @@ angular.module('Engine2', ['ngRoute', 'ngSanitize', 'ngAnimate', 'ngCookies', 'm
446
488
  elem.off "mousedown"
447
489
  # event.preventDefault()
448
490
  # event.stopPropagation()
449
- dropdown = $dropdown(elem, (scope: scope, template: render($parse(attrs.e2DropDown)(scope), 0), animation: 'am-flip-x', prefixEvent: "#{event_num}.tooltip")) # , delay: 1
491
+ menu = $parse(attrs.e2Dropdown)(scope)
492
+ dropdown = $dropdown(elem, (scope: scope, template: render(menu, 0), animation: attrs.animation || 'am-flip-x', prefixEvent: "#{event_num}.tooltip")) # , delay: 1
450
493
  dropdown.$promise.then ->
451
494
  event_hide = scope.$on "#{event_num}.tooltip.hide", (e) ->
452
495
  e.stopPropagation()
@@ -463,13 +506,14 @@ angular.module('Engine2', ['ngRoute', 'ngSanitize', 'ngAnimate', 'ngCookies', 'm
463
506
 
464
507
  .directive 'e2ButtonSet', ($parse, $compile, E2Snippets) ->
465
508
  button_set_tmpl = _.template("<div class='btn btn-default' {{clazz}} {{click}} {{show}} {{hide}} {{title}}> {{icon}}{{aicon}} {{loc}}</div>")
466
- button_set_arr_tmpl = _.template("<div class='btn btn-default' e2-drop-down='{{dropdown}}'>{{icon}}{{aicon}}<span class='caret'></span></div>")
509
+ button_set_arr_tmpl = _.template("<div class='btn btn-default' e2-dropdown='{{dropdown}}' data-animation='{{animation}}'>{{icon}}{{aicon}}<span class='caret'></span></div>")
467
510
  scope: true # because $index
468
511
  link: (scope, elem, attrs) ->
469
512
  menu = $parse(attrs.e2ButtonSet)(scope)
470
513
  if menu && menu.entries.length > 0
471
514
  group_class = menu.properties.group_class || ''
472
515
  brk = menu.properties.break
516
+ animation = menu.properties.animation
473
517
  out = ""
474
518
  for m, i in menu.entries
475
519
  if i >= brk
@@ -477,6 +521,7 @@ angular.module('Engine2', ['ngRoute', 'ngSanitize', 'ngAnimate', 'ngCookies', 'm
477
521
  else if m.menu
478
522
  out += button_set_arr_tmpl
479
523
  dropdown: "#{attrs.e2ButtonSet}.entries[#{i}].menu.entries"
524
+ animation: animation
480
525
  icon: m.menu.icon && "#{E2Snippets.icon(m.menu.icon)}&nbsp;" || ''
481
526
  aicon: m.menu.aicon && "#{E2Snippets.aicon(m.menu.aicon)}&nbsp;" || ''
482
527
  else if m.divider
@@ -491,7 +536,13 @@ angular.module('Engine2', ['ngRoute', 'ngSanitize', 'ngAnimate', 'ngCookies', 'm
491
536
  loc: !(m.button_loc == false) && m.loc || ''
492
537
  title: (m.button_loc == false) && "title=\"#{m.loc}\"" || ''
493
538
 
494
- out += button_set_arr_tmpl dropdown: "#{attrs.e2ButtonSet}.entries.slice(#{brk})", icon: '', aicon: '' if menu.entries.length > brk
539
+ if menu.entries.length > brk
540
+ out += button_set_arr_tmpl
541
+ dropdown: "#{attrs.e2ButtonSet}.entries.slice(#{brk})"
542
+ animation: animation
543
+ icon: ''
544
+ aicon: ''
545
+
495
546
  out = "<div class='btn-group #{group_class}'>#{out}</div>"
496
547
  out = $compile(angular.element(out))(scope)
497
548
  if attrs.index && !scope.$index?
@@ -1,3 +1,4 @@
1
+ 'use strict'
1
2
  angular.module('Engine2')
2
3
  .directive 'e2Action', (E2Actions) ->
3
4
  scope: true
@@ -22,7 +23,7 @@ angular.module('Engine2')
22
23
  $scope.action = new E2Actions.root(mresponse.data, $scope, null, $element, action_resource: 'api')
23
24
 
24
25
  .factory 'E2Actions', (E2, $http, $timeout, $e2Modal, $injector, $compile, $templateCache, $q, localStorageService, $route, $window, $rootScope, $location) ->
25
- globals = {}
26
+ globals = E2.globals
26
27
  action: class Action
27
28
  constructor: (response, scope, parent, element, action_info) ->
28
29
  @find_action_info = (name, raise = true) ->
@@ -71,14 +72,17 @@ angular.module('Engine2')
71
72
 
72
73
  perform_invoke: (params) ->
73
74
  info = @action_info()
74
- get_invoke = if info.invokable
75
- params.initial = true if !@action_invoked && params && info.method == 'get'
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'
76
77
  $http[info.method](info.action_resource, if info.method == 'post' then params else (params: params))
77
- else $q.when(data: (response: {}))
78
78
 
79
79
  globals.action_pending = if @meta.panel then @ else @parent()
80
80
 
81
81
  get_invoke.then (response) =>
82
+ if exec = response.data.$execute
83
+ @scope().$eval(exec)
84
+ delete response.data.$execute
85
+
82
86
  E2.merge(@, response.data)
83
87
  @process_meta()
84
88
  (if @meta.reload_routes then $route.load_routes() else $q.when({})).then =>
@@ -103,7 +107,7 @@ angular.module('Engine2')
103
107
  get_meta = if !info.terminal || info.meta
104
108
  $http.get("#{info.action_resource}/meta", cache: true).then (response) =>
105
109
  if info.recheck_access
106
- $http.get("#{info.action_resource}/meta", params: (access: true, parent_id: @current_id)).then (aresponse) ->
110
+ $http.get("#{info.action_resource}/meta", params: (access: true, parent_id: @current_id())).then (aresponse) ->
107
111
  response.data.actions[k].access = v for k, v of aresponse.data
108
112
  response
109
113
  else response # $q.when ^
@@ -113,8 +117,8 @@ angular.module('Engine2')
113
117
  ,
114
118
  (err) => @handle_error(err, info, el)
115
119
 
116
- invoke_action: (name, arg) ->
117
- @create_action(name, @scope()).then (act) -> act.invoke(arg)
120
+ invoke_action: (name, args) ->
121
+ @create_action(name, @scope()).then (act) -> act.invoke(args)
118
122
 
119
123
  create_action_path: (action_names, sc, elem) ->
120
124
  last_name = action_names.pop()
@@ -126,17 +130,23 @@ angular.module('Engine2')
126
130
  pre_invoke: ->
127
131
  post_invoke: ->
128
132
 
129
- invoke: ->
130
- args = arguments
131
- @pre_invoke(args...)
132
- @perform_invoke(args...).then (response) =>
133
- @post_invoke(args...)
133
+ invoke: (args) ->
134
+ @pre_invoke(args)
135
+ _.merge(args ?= {}, @meta.arguments) if @meta.arguments
136
+ @perform_invoke(args).then =>
137
+ @post_invoke(args)
138
+ @scope().$eval(@meta.execute) if @meta.execute
139
+ 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
134
144
  @
135
145
 
136
146
  save_state: () ->
137
147
  _.each @meta.state, (s) => localStorageService.set("#{globals.application}/#{@action_info().action_resource}/#{s}", @[s])
138
148
  load_state: () ->
139
- _.each @meta.state, (s) => E2.merge(@[s], localStorageService.get("#{globals.application}/#{@action_info().action_resource}/#{s}"))
149
+ _.each @meta.state, (s) => _.merge(@[s], localStorageService.get("#{globals.application}/#{@action_info().action_resource}/#{s}"))
140
150
 
141
151
  destroy: (e) ->
142
152
  console.log "DESTROY #{@action_info().action_resource}"
@@ -194,7 +204,7 @@ angular.module('Engine2')
194
204
  root: class RootAction extends Action
195
205
  initialize: ->
196
206
  super()
197
- E2.merge(globals, @meta)
207
+ _.merge(globals, @meta)
198
208
  @meta = {}
199
209
 
200
210
  default_action: class DefaultAction extends Action
@@ -266,10 +276,13 @@ angular.module('Engine2')
266
276
  if route.menu then @register(route.menu.entries) else
267
277
  name = '/' + route.name
268
278
  route.href = '#' + route.name
269
- $templateCache.put(route.name, "<div e2-action='' action=\"'#{route.bootstrap}/#{route.name}'\" invoke='true'></div>") if route.bootstrap
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
+
270
283
  $route.routes[name] =
271
284
  reloadOnSearch: true
272
- templateUrl: route.name
285
+ templateUrl: if route.bootstrap? then route.name + '_route_template!' else route.name
273
286
  originalPath: name
274
287
  regexp: new RegExp("^#{name}$")
275
288
  keys: []
@@ -282,14 +295,16 @@ angular.module('Engine2')
282
295
 
283
296
  traverse: (routes) ->
284
297
  menu_tmpl = _.template("<li><a href='{{href}}'>{{icon}}{{aicon}} {{loc}}</a></li>")
285
- menu_sub_tmpl = _.template("<li e2-drop-down='{{dropdown}}'><a href='javascript://'>{{icon}}{{aicon}} {{loc}}<span class='caret'></span></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>")
299
+ animation = @meta.menus.menu.properties.animation
286
300
  out = routes.map (route, i) ->
287
301
  if route.menu
288
302
  menu_sub_tmpl
303
+ dropdown: "routes[#{i}].menu.entries"
304
+ animation: animation
289
305
  icon: route.menu.icon && E2.icon(route.menu.icon) || ""
290
306
  aicon: route.menu.aicon && E2.aicon(route.menu.aicon) || ""
291
307
  loc: route.menu.loc
292
- dropdown: "routes[#{i}].menu.entries"
293
308
  else
294
309
  menu_tmpl
295
310
  href: route.href
@@ -298,8 +313,6 @@ angular.module('Engine2')
298
313
  aicon: route.aicon && E2.aicon(route.aicon) || ''
299
314
  out.join('')
300
315
 
301
- # dummy: class DummyAction extends Action
302
-
303
316
  list: class ListAction extends Action
304
317
  initialize: ->
305
318
  super()
@@ -340,7 +353,7 @@ angular.module('Engine2')
340
353
  menu_show_meta: ->
341
354
  $e2Modal.show
342
355
  the_meta: @meta
343
- meta: panel: (panel_template: "close_m", template_string: "<pre>{{action.the_meta | json}}</pre>", title: "Meta", class: "modal-huge")
356
+ meta: panel: (panel_template: "close_m", template_string: "<pre>{{action.the_meta | json}}</pre>", title: "Meta", class: "modal-huge", backdrop: true, footer: true)
344
357
 
345
358
  # show_assoc: (index, assoc) ->
346
359
  # # parent_id = E2.id_for(@entries[index], @meta)
@@ -350,14 +363,20 @@ angular.module('Engine2')
350
363
  # @current_id = E2.id_for(@entries[index], @meta)
351
364
  # @invoke_action(assoc)
352
365
 
366
+ current_entry: ->
367
+ @entries[@current_index]
368
+
369
+ current_id: ->
370
+ E2.id_for(@current_entry(), @meta)
371
+
353
372
  list_cell: (e, f) ->
354
373
  E2.render_field(e, f, @meta)
355
374
 
356
- invoke: (arg = {}) ->
375
+ invoke: (args = {}) ->
357
376
  @save_state()
358
377
  query = _.cloneDeep(@query)
359
378
  delete query.search if _.isEmpty(E2.compact(query.search))
360
- _.merge(query, arg)
379
+ _.merge(query, args)
361
380
  super(query).then =>
362
381
  @ui = _.pick @query, ['order', 'asc', 'page']
363
382
  @ui.pagination_active = @ui.page != 0 || @entries.length >= @meta.config.per_page
@@ -599,7 +618,7 @@ angular.module('Engine2')
599
618
  @multiple = @dinfo.render.multiple
600
619
  @clear_selected()
601
620
  @if_fk_values (fk_values) =>
602
- @selected = if @multiple then E2.transpose(fk_values).map(E2.join_keys) else E2.join_keys(fk_values)
621
+ @selected = if @multiple then E2.transpose(fk_values).map((e) -> E2.join_keys(e)) else E2.join_keys(fk_values)
603
622
  @invoke()
604
623
 
605
624
  clear_selected: -> @selected = if @multiple then [] else null # no need to null complex keys
@@ -652,7 +671,7 @@ angular.module('Engine2')
652
671
 
653
672
  invoke_decode: (recs, f) ->
654
673
  if @multiple && _.size(recs) > @meta.show_max_selected
655
- @decode = "#{_.size(recs)} #{@meta.decode_selected}"
674
+ @decode = "#{_.size(recs)} #{@meta.loc.decode_selected}"
656
675
  else
657
676
  decode_descriptions = (recs) => @decode = recs.map((fields) => @decode_description(fields)).join(' | ')
658
677
  recs = recs.map (r) => if _.isArray(r) then E2.from_id(r, @meta) else r
@@ -721,7 +740,7 @@ angular.module('Engine2')
721
740
  star_to_many_list: class StarToManyList extends ListAction
722
741
  initialize: ->
723
742
  super()
724
- @query.parent_id = @parent().current_id
743
+ @query.parent_id = @parent().current_id()
725
744
 
726
745
  # link_list: implicit
727
746
  item_menu_confirm_unlink: (index) ->
@@ -786,8 +805,8 @@ angular.module('Engine2')
786
805
  @panel_close()
787
806
 
788
807
  star_to_many_field_unlink: class StarToManyFieldUnlink extends Action
789
- invoke: (arg) ->
790
- id = arg.id
808
+ invoke: (args) ->
809
+ id = args.id
791
810
  pparent = @parent().parent()
792
811
  if _.includes(pparent.links.linked, id) then _.pull(pparent.links.linked, id) else pparent.links.unlinked.push id
793
812
  pparent.sync_record()