engine2 1.0.4 → 1.0.9

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.
Files changed (131) hide show
  1. checksums.yaml +5 -5
  2. data/Gemfile +0 -0
  3. data/Rakefile +4 -4
  4. data/app/{engine2actions.coffee → actions.coffee} +341 -215
  5. data/app/app.coffee +0 -0
  6. data/app/app.css +17 -0
  7. data/app/engine2.coffee +158 -208
  8. data/app/modal.coffee +138 -0
  9. data/bower.json +4 -2
  10. data/conf/message.yaml +5 -0
  11. data/conf/message_pl.yaml +7 -2
  12. data/config.coffee +24 -12
  13. data/engine2.gemspec +8 -8
  14. data/lib/engine2.rb +12 -10
  15. data/lib/engine2/action.rb +1338 -133
  16. data/lib/engine2/action/array.rb +189 -0
  17. data/lib/engine2/{meta/decode_meta.rb → action/decode.rb} +52 -21
  18. data/lib/engine2/action/delete.rb +64 -0
  19. data/lib/engine2/action/form.rb +16 -0
  20. data/lib/engine2/{meta/infra_meta.rb → action/infra.rb} +123 -89
  21. data/lib/engine2/action/link.rb +117 -0
  22. data/lib/engine2/action/list.rb +333 -0
  23. data/lib/engine2/action/save.rb +28 -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 +175 -87
  27. data/lib/engine2/handler.rb +14 -13
  28. data/lib/engine2/model.rb +85 -43
  29. data/lib/engine2/models/Files.rb +4 -1
  30. data/lib/engine2/models/UserInfo.rb +6 -3
  31. data/lib/engine2/post_bootstrap.rb +4 -3
  32. data/lib/engine2/pre_bootstrap.rb +10 -6
  33. data/lib/engine2/scheme.rb +107 -65
  34. data/lib/engine2/templates.rb +41 -6
  35. data/lib/engine2/type_info.rb +51 -23
  36. data/lib/engine2/version.rb +2 -1
  37. data/package.json +22 -16
  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 +1 -1
  42. data/views/fields/bs_select.slim +2 -2
  43. data/views/fields/bsselect_picker.slim +4 -4
  44. data/views/fields/bsselect_picker_opt.slim +5 -5
  45. data/views/fields/checkbox.slim +4 -4
  46. data/views/fields/checkbox_button.slim +6 -0
  47. data/views/fields/checkbox_buttons.slim +3 -3
  48. data/views/fields/checkbox_buttons_opt.slim +3 -3
  49. data/views/fields/currency.slim +2 -2
  50. data/views/fields/date.slim +4 -4
  51. data/views/fields/date_range.slim +9 -9
  52. data/views/fields/date_time.slim +9 -9
  53. data/views/fields/datetime.slim +8 -8
  54. data/views/fields/decimal.slim +1 -1
  55. data/views/fields/decimal_date.slim +3 -3
  56. data/views/fields/decimal_time.slim +3 -3
  57. data/views/fields/email.slim +3 -3
  58. data/views/fields/file_store.slim +11 -11
  59. data/views/fields/input_text.slim +4 -4
  60. data/views/fields/integer.slim +1 -1
  61. data/views/fields/list_bsmselect.slim +20 -0
  62. data/views/fields/list_bsselect.slim +5 -5
  63. data/views/fields/list_bsselect_opt.slim +6 -6
  64. data/views/fields/list_buttons.slim +1 -1
  65. data/views/fields/list_buttons_opt.slim +2 -2
  66. data/views/fields/list_mbuttons.slim +9 -0
  67. data/views/fields/list_mbuttons_opt.slim +11 -0
  68. data/views/fields/list_mselect.slim +12 -0
  69. data/views/fields/list_select.slim +4 -4
  70. data/views/fields/list_select_opt.slim +5 -5
  71. data/views/fields/password.slim +4 -4
  72. data/views/fields/radio_checkbox.slim +3 -3
  73. data/views/fields/scaffold.slim +2 -2
  74. data/views/fields/scaffold_picker.slim +5 -5
  75. data/views/fields/select_picker.slim +3 -3
  76. data/views/fields/select_picker_opt.slim +4 -4
  77. data/views/fields/text_area.slim +4 -3
  78. data/views/fields/time.slim +5 -4
  79. data/views/fields/typeahead_picker.slim +12 -9
  80. data/views/index.slim +3 -3
  81. data/views/infra/index.slim +0 -0
  82. data/views/infra/inspect.slim +41 -10
  83. data/views/modals/close_m.slim +0 -0
  84. data/views/modals/confirm_m.slim +0 -0
  85. data/views/modals/empty_m.slim +0 -0
  86. data/views/modals/menu_m.slim +1 -1
  87. data/views/modals/yes_no_m.slim +0 -0
  88. data/views/panels/menu_m.slim +1 -1
  89. data/views/scaffold/confirm.slim +0 -0
  90. data/views/scaffold/fields.slim +6 -4
  91. data/views/scaffold/form.slim +1 -1
  92. data/views/scaffold/form_collapse.slim +4 -3
  93. data/views/scaffold/form_tabs.slim +3 -2
  94. data/views/scaffold/list.slim +0 -0
  95. data/views/scaffold/message.slim +0 -0
  96. data/views/scaffold/search.slim +4 -4
  97. data/views/scaffold/search_collapse.slim +8 -7
  98. data/views/scaffold/search_tabs.slim +6 -5
  99. data/views/scaffold/view.slim +2 -2
  100. data/views/scaffold/view_collapse.slim +5 -4
  101. data/views/scaffold/view_tabs.slim +4 -3
  102. data/views/search_fields/bsmselect_picker.slim +4 -4
  103. data/views/search_fields/bsselect_picker.slim +4 -4
  104. data/views/search_fields/checkbox.slim +3 -3
  105. data/views/search_fields/checkbox2.slim +5 -5
  106. data/views/search_fields/checkbox_buttons.slim +3 -3
  107. data/views/search_fields/date.slim +20 -0
  108. data/views/search_fields/date_range.slim +8 -8
  109. data/views/search_fields/decimal_date_range.slim +5 -5
  110. data/views/search_fields/input_text.slim +2 -2
  111. data/views/search_fields/integer.slim +1 -1
  112. data/views/search_fields/integer_range.slim +2 -2
  113. data/views/search_fields/list_bsmselect.slim +4 -4
  114. data/views/search_fields/list_bsselect.slim +4 -4
  115. data/views/search_fields/list_buttons.slim +2 -2
  116. data/views/search_fields/list_mbuttons.slim +12 -0
  117. data/views/search_fields/list_select.slim +3 -3
  118. data/views/search_fields/scaffold_picker.slim +2 -2
  119. data/views/search_fields/select_picker.slim +3 -3
  120. data/views/search_fields/typeahead_picker.slim +8 -7
  121. metadata +53 -48
  122. data/lib/engine2/meta.rb +0 -1216
  123. data/lib/engine2/meta/array_meta.rb +0 -82
  124. data/lib/engine2/meta/delete_meta.rb +0 -60
  125. data/lib/engine2/meta/form_meta.rb +0 -15
  126. data/lib/engine2/meta/link_meta.rb +0 -134
  127. data/lib/engine2/meta/list_meta.rb +0 -281
  128. data/lib/engine2/meta/save_meta.rb +0 -50
  129. data/lib/engine2/meta/view_meta.rb +0 -7
  130. data/public/__sinatra__/404.png +0 -0
  131. data/public/__sinatra__/500.png +0 -0
File without changes
@@ -61,6 +61,11 @@ tr.tr_hover {
61
61
  font-weight:normal;
62
62
  }
63
63
 
64
+ textarea {
65
+ /*white-space: nowrap;*/
66
+ white-space: pre-wrap;
67
+ }
68
+
64
69
  /*.modal-backdrop{
65
70
  position:fixed;
66
71
  top:0;
@@ -201,3 +206,15 @@ button {
201
206
  }*/
202
207
 
203
208
  a[ng-click] {cursor:pointer;}
209
+
210
+ .dndDragging {
211
+ }
212
+
213
+ .dndDraggingSource {
214
+ }
215
+
216
+ .dndPlaceholder{
217
+ }
218
+
219
+ .dndDragover {
220
+ }
@@ -1,34 +1,71 @@
1
1
  'use strict'
2
- require 'angular-route'
3
2
  require 'angular-sanitize'
4
3
  require 'angular-animate'
5
4
  require 'angular-cookies'
6
5
  require 'angular-local-storage'
7
6
  require 'angular-ui-tree'
7
+ require '@uirouter/core'
8
+ require '@uirouter/angularjs'
8
9
  require 'ng-file-upload'
10
+ require 'angular-load'
11
+ require 'angular-drag-and-drop-lists'
12
+ # require 'ui-select'
9
13
 
10
14
  _.templateSettings.interpolate = /{{([\s\S]+?)}}/g;
11
15
 
12
- angular.module('Engine2', ['ngRoute', 'ngSanitize', 'ngAnimate', 'ngCookies', 'mgcrea.ngStrap', 'ngFileUpload', 'ui.tree', 'LocalStorageModule']) # 'draggabilly'
13
- .config ($httpProvider, $routeProvider, $compileProvider, localStorageServiceProvider, $logProvider) ->
14
- loaderOn = -> angular.element(document.querySelectorAll('.loader')).eq(-1).css("visibility", 'visible')
16
+ angular.module('Engine2', ['ngSanitize', 'ngAnimate', 'ngCookies', 'mgcrea.ngStrap', 'ngFileUpload', 'ui.tree', 'LocalStorageModule', 'angularLoad', 'ngWebSocket', 'ui.router', 'dndLists', 'toastr']) # 'ui.select'
17
+ .config ($httpProvider, $compileProvider, localStorageServiceProvider, $logProvider, $qProvider, $locationProvider, $provide) ->
15
18
  $httpProvider.interceptors.push 'e2HttpInterceptor'
16
- $httpProvider.defaults.transformRequest.push (data, headersGetter) ->
17
- loaderOn()
18
- data
19
+ $provide.decorator '$httpBackend', ($delegate) ->
20
+ (method, url, post, callback, headers, timeout, withCredentials, responseType) ->
21
+ url = url.replace(/;/g, '%3B') unless method == 'POST'
22
+ $delegate(method, url, post, callback, headers, timeout, withCredentials, responseType)
19
23
  # $httpProvider.defaults.headers.common['Cache-Control'] = 'no-cache'
20
24
  # $httpProvider.defaults.cache = false;
21
- $httpProvider.defaults.headers.get ||= {} # if !$httpProvider.defaults.headers.get
25
+ $httpProvider.defaults.headers.get ?= {} # if !$httpProvider.defaults.headers.get
22
26
  $httpProvider.defaults.headers.get['If-Modified-Since'] = '0'
23
27
  # localStorageServiceProvider.setStorageType('sessionStorage')
24
28
  localStorageServiceProvider.setPrefix('E2')
25
29
  $compileProvider.debugInfoEnabled(false)
26
30
  $logProvider.debugEnabled(true)
27
31
  $httpProvider.useApplyAsync(true)
28
- # $locationProvider.html5Mode(true);
29
-
32
+ # $qProvider.errorOnUnhandledRejections(false)
33
+ # $locationProvider.hashPrefix('')
34
+ # $locationProvider.html5Mode(false)
35
+ $provide.decorator 'ngModelDirective', ($delegate) ->
36
+ directive = $delegate[0]
37
+ compile = directive.compile
38
+ directive.compile = (elem, attrs, trans) ->
39
+ comp = compile(elem, attrs, trans)
40
+ pre: comp.pre
41
+ post: (scope, element, attr, ctrls) ->
42
+ ctrls[0].$parsers.push (vw) -> if vw == "" then null else vw
43
+ comp.post(scope, element, attr, ctrls)
44
+ $delegate
45
+
46
+ .factory 'PushJS', -> require 'push.js'
47
+ .factory 'PrettyYAML', -> require 'json-to-pretty-yaml'
48
+ .filter 'yaml', (PrettyYAML) -> (input) -> PrettyYAML.stringify(input, 4)
49
+
50
+ .factory 'MetaCache', ($cacheFactory) -> $cacheFactory('MetaCache')
30
51
  .factory 'e2HttpInterceptor', ($q, $injector, E2Snippets) ->
31
- loaderOff = -> angular.element(document.querySelectorAll('.loader')).eq(-1).css("visibility", 'hidden')
52
+ loaderToggle = (toggle) -> angular.element(document.querySelectorAll('.loader')).eq(-1).css("visibility", toggle)
53
+ loaderOn = -> loaderToggle('visible')
54
+ timeout = null
55
+ loaderOff = ->
56
+ if timeout
57
+ clearTimeout timeout
58
+ timeout = null
59
+ loaderToggle('hidden')
60
+
61
+ request: (request) ->
62
+ if timeout
63
+ clearTimeout timeout
64
+ timeout = null
65
+ else
66
+ timeout = setTimeout(loaderOn, 200)
67
+ request
68
+
32
69
  response: (response) ->
33
70
  loaderOff()
34
71
  response
@@ -47,21 +84,38 @@ angular.module('Engine2', ['ngRoute', 'ngSanitize', 'ngAnimate', 'ngCookies', 'm
47
84
  $q.reject(response)
48
85
 
49
86
  .factory 'E2Snippets', ->
50
- icon = (name) -> "<span class='glyphicon glyphicon-#{name}'></span>"
51
- aicon = (name) -> "<i class='fa fa-#{name}'></i>"
87
+ icon = (name) ->
88
+ if name.slice(0, 3) == 'fa_'
89
+ "<i class='fa fa-#{name.slice(3)}'></i>"
90
+ else
91
+ "<span class='glyphicon glyphicon-#{name}'></span>"
92
+
52
93
  ng_class_names = ['active', 'enabled', 'disabled']
53
94
  icon: icon
54
- aicon: aicon
55
95
  boolean_true_value: icon('check')
56
96
  boolean_false_value: icon('unchecked')
57
97
  make_ng_class: (o) ->
58
98
  out = []
59
99
  _.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?
100
+ _.each(o.class, (v, k) -> out.push "'#{k}': #{v}") if o.class?
61
101
  if out.length > 0 then "ng-class=\"{#{out.join(',')}}\"" else ""
62
102
 
63
- .factory 'E2', ($templateCache, $http, E2Snippets, $e2Modal, $q, $injector, e2HttpInterceptor, $route, $dateFormatter, $parse) ->
64
- globals: {}
103
+ .factory 'E2', ($templateCache, $http, E2Snippets, $q, $dateFormatter, $parse, PushJS, $state, $e2Modal, toastr) ->
104
+ globals:
105
+ element: (id) ->
106
+ element = document.querySelector(id)
107
+ console.warn "Element #{id} not found" unless element
108
+ element
109
+
110
+ notification: (name, body, icon, timeoutx, on_close) ->
111
+ PushJS.create name, body: body, icon: icon, timeout: timeoutx, onClick: on_close
112
+
113
+ toastr: -> toastr
114
+ state: -> $state
115
+ modal: -> $e2Modal
116
+
117
+ uuid: (length) ->
118
+ Math.random().toString(10).substr(2, 8)
65
119
 
66
120
  compact: (o) ->
67
121
  _.each o, (v, k) =>
@@ -75,18 +129,19 @@ angular.module('Engine2', ['ngRoute', 'ngSanitize', 'ngAnimate', 'ngCookies', 'm
75
129
  else if _.isObject(v) && !_.isDate(v)
76
130
  @clean(v)
77
131
  else
78
- # delete o[k]
79
- o[k] = null
132
+ o[k] = null # delete o[k]
80
133
 
81
- merge: (dst, src) ->
134
+ merge_meta: (dst, src) ->
82
135
  for k, v of src
83
- if _.isObject(v) && !_.isArray(v)
84
- if k.slice(-1) == '!'
85
- dst[k.slice(0, -1)] = v
86
- else
87
- dst[k] = @merge(dst[k] ? {}, v)
136
+ throw "Attempted to override function '#{k}'" if _.isFunction(dst[k])
137
+ if (k == 'execute' || k == 'pre_execute') && dst[k] && src[k]
138
+ dst[k] = dst[k].concat(src[k])
88
139
  else
89
- dst[k] = v
140
+ insn = k.slice(-1)
141
+ if _.isObject(v) && !_.isArray(v)
142
+ if insn == '!' then dst[k.slice(0, -1)] = v else dst[k] = @merge_meta(dst[k] ? {}, v)
143
+ else
144
+ if insn == '?' then dst[k.slice(0, -1)] ?= v else dst[k] = v
90
145
  dst
91
146
 
92
147
  transpose: (a) ->
@@ -98,7 +153,6 @@ angular.module('Engine2', ['ngRoute', 'ngSanitize', 'ngAnimate', 'ngCookies', 'm
98
153
  from_id: (id, meta) -> _.zipObject(meta.primary_fields, id) # _.zip(meta.primary_fields, id).reduce(((rec, [k, v]) -> rec[k] = v; rec), {})
99
154
 
100
155
  icon: E2Snippets.icon
101
- aicon: E2Snippets.aicon
102
156
 
103
157
  fetch_template: (template) ->
104
158
  $q.when($templateCache.get(template) || $http.get(template)).then (res) ->
@@ -137,11 +191,21 @@ angular.module('Engine2', ['ngRoute', 'ngSanitize', 'ngAnimate', 'ngCookies', 'm
137
191
  processor.arg_fun(action, arg)
138
192
  action.scope().$eval(click)
139
193
  else
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)
194
+ if ofun = action[fun_name]
195
+ action["#{fun_name}_super"] = (args) ->
196
+ _.merge(args, $parse(m.arguments)(action.scope())) if m.arguments?
197
+ action.invoke_action(m.name, args)
198
+
199
+ action[fun_name] = (args) ->
200
+ processor.arg_fun(action, args)
201
+ args = processor.arg_ret(action)
202
+ ofun.bind(action)(args)
203
+ else
204
+ action[fun_name] = (arg) ->
205
+ processor.arg_fun(action, arg)
206
+ args = processor.arg_ret(action)
207
+ _.merge(args, $parse(m.arguments)(action.scope())) if m.arguments?
208
+ action.invoke_action(m.name, args)
145
209
 
146
210
  if action.find_action_info(m.name, false)?
147
211
  show = if m.show then " && " + m.show else ""
@@ -167,11 +231,14 @@ angular.module('Engine2', ['ngRoute', 'ngSanitize', 'ngAnimate', 'ngCookies', 'm
167
231
  when render.true_value then E2Snippets.boolean_true_value
168
232
  when render.false_value then E2Snippets.boolean_false_value
169
233
  else "?"
170
- list_select: (value, render) ->
171
- render.list_hash ||= render.list.reduce(((h, [a, b]) -> h[a] = b; h), {})
172
- render.list_hash[value] ? value
234
+ list_select: (value, render, separator) ->
235
+ render.list_hash ||= render.values.reduce(((h, [a, b]) -> h[a] = b; h), {})
236
+ if render.multiselect && _.isArray(value)
237
+ value.map((v) -> render.list_hash[v] ? ":#{value}:").join(separator)
238
+ else
239
+ render.list_hash[value] ? ":#{value}:"
173
240
  datetime: (value, render) ->
174
- value.split('\.')[0]
241
+ value.split('\.')[0].split(' ', 2).join(' ')
175
242
  # $dateFormatter.formatDate(value, "yyyy-MM-dd", $dateFormatter.getDefaultLocale())
176
243
  integer: (value, render) -> # ?
177
244
  value.toString()
@@ -186,12 +253,12 @@ angular.module('Engine2', ['ngRoute', 'ngSanitize', 'ngAnimate', 'ngCookies', 'm
186
253
  value.toString()
187
254
 
188
255
 
189
- render_field: (entry, name, meta) ->
256
+ render_field: (entry, name, meta, separator) ->
190
257
  value = entry[name]
191
- if value? && info = meta.info
258
+ if value? && info = meta.fields
192
259
  f_info = info[name]
193
260
  if f_info? && type = f_info.type
194
- @renderers[type](value, f_info.render)
261
+ @renderers[type](value, f_info.render, separator)
195
262
  else
196
263
  if f_info?.escape == false then value else
197
264
  (value + "").replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;")
@@ -206,138 +273,6 @@ angular.module('Engine2', ['ngRoute', 'ngSanitize', 'ngAnimate', 'ngCookies', 'm
206
273
  parser = @parsers[info.type]
207
274
  if parser then parser(value, info) else value
208
275
 
209
- .provider '$e2Modal', ->
210
- $get: ($rootScope, $modal, $timeout, $window, $injector) ->
211
- class MManager
212
- @Z_INDEX: 1050
213
- @index: 0
214
- constructor: () ->
215
- backdrop_z_index: (num, index) -> angular.element(document.querySelectorAll('.modal-backdrop')).eq(num).css('z-index', index)
216
- modal_num: (num) -> angular.element(document.querySelectorAll('.modal')).eq(num)
217
- backdrop: (bdr) -> bdr ? 'static'
218
- show_before: ->
219
- @z_index = MManager.Z_INDEX + MManager.index * 2
220
- @modal.css('z-index', @z_index + 1)
221
- hide_before: ->
222
- @z_index = MManager.Z_INDEX + ((MManager.index - 1) * 2)
223
- show: ->
224
- hide: -> angular.element($window.document.body).addClass('modal-open modal-with-am-fade') if MManager.index > 0
225
-
226
- class DefaultMManager extends MManager
227
- show_before: ->
228
- super()
229
- @backdrop.css('z-index', @z_index) # @backdrop_z_index(-MManager.index - 1, z_index)
230
-
231
- class FirstMManager extends MManager
232
- constructor: () ->
233
- super()
234
- @threshold = 2
235
- backdrop: (bdr) -> if MManager.index > @threshold then false else super(bdr)
236
- show_before: ->
237
- super()
238
- if MManager.index > @threshold
239
- @modal_num((MManager.index - 1) - @threshold).css('display', 'none')
240
- @backdrop_z_index(0, @z_index)
241
- else
242
- @backdrop.css('z-index', @z_index) # @backdrop_z_index(-MManager.index - 1, z_index)
243
-
244
- hide_before: ->
245
- super()
246
- if MManager.index > @threshold
247
- @backdrop_z_index(0, @z_index)
248
- @modal_num((MManager.index - 1) - @threshold).css('display', 'block')
249
-
250
- class SingleBackdropMManager extends MManager
251
- backdrop: (bdr) -> if MManager.index > 0 then false else super(bdr)
252
- show_before: ->
253
- super()
254
- @backdrop_z_index(0, @z_index)
255
- hide_before: ->
256
- super()
257
- @backdrop_z_index(0, @z_index)
258
-
259
- is_modal: -> MManager.index > 0
260
-
261
- show: (action) ->
262
- scope = if action.scope then action.scope().$new(true) else $rootScope.$new()
263
- scope.action = action
264
- manager = new SingleBackdropMManager()
265
-
266
- scope.$on 'modal.show.before', (e, m) ->
267
- e.stopPropagation()
268
- manager.modal = m.$element
269
- manager.backdrop = m.$backdrop
270
- throw "Modal has element" if action.element?()
271
- action.element = -> m.$element
272
- action.panel_show?()
273
- manager.show_before()
274
- MManager.index++
275
-
276
- scope.$on 'modal.show', (e, m) ->
277
- e.stopPropagation()
278
- manager.show()
279
- action.panel_shown?()
280
-
281
- scope.$on 'modal.hide.before', (e) ->
282
- e.stopPropagation()
283
- MManager.index--
284
- manager.hide_before()
285
- action.panel_hide?()
286
-
287
- scope.$on 'modal.hide', (e) ->
288
- e.stopPropagation()
289
- manager.hide()
290
- action.panel_hidden?()
291
- scope.$destroy()
292
-
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()
302
- modal.$promise.then ->
303
- modal.show()
304
- modal
305
-
306
- error: (title, msg, html) ->
307
- body = if html then msg else "<div class='alert alert-danger'>#{msg}</div>"
308
- clazz = if html then "modal-huge" else "modal-large"
309
- @show meta: panel: (panel_template: "close_m", template_string: body, title: title, class: clazz, footer: true) # message: msg,
310
-
311
- confirm: (title, msg, action) ->
312
- body = "<div class='alert alert-warning'>#{msg}</div>"
313
- clazz = "modal-large"
314
- @show
315
- confirm: action,
316
- meta: panel: (panel_template: "confirm_m", template_string: body, title: title, class: clazz, footer: true) # message: msg,
317
-
318
- .directive 'e2Modal', ($e2Modal) ->
319
- restrict: 'E'
320
- # replace: true
321
- # transclude: true
322
- scope: true
323
- compile: (celem, cattr) ->
324
- obody = celem[0].children[0]
325
- celem.empty() if obody
326
- (scope, elem, attrs) ->
327
- scope.$on attrs.name, (ev, args) ->
328
- return if ev.defaultPrevented
329
- ev.preventDefault()
330
-
331
- panel = panel_template: attrs.panelTemplate, title: attrs.title, class: attrs.clazz, footer: true
332
- if obody then panel.template_string = obody.outerHTML else panel.template = attrs.template
333
- action = meta: (panel: panel), scope: -> scope
334
- _.assign(action, args)
335
-
336
- modal = $e2Modal.show(action)
337
- hide_off = scope.$on "#{attrs.name}_close", ->
338
- hide_off()
339
- modal.then (m) -> m.$scope.$hide()
340
-
341
276
  .directive 'e2Field', ($timeout, $filter) ->
342
277
  require: 'ngModel'
343
278
  restrict: 'A'
@@ -347,7 +282,7 @@ angular.module('Engine2', ['ngRoute', 'ngSanitize', 'ngAnimate', 'ngCookies', 'm
347
282
 
348
283
  name = attrs.e2Field || scope.f
349
284
  meta = scope.action.meta
350
- info = meta.info[name]
285
+ info = meta.fields[name]
351
286
  scope.$on "focus_field", (event, n, mode) ->
352
287
  if n == name
353
288
  elem[0].focus()
@@ -360,8 +295,8 @@ angular.module('Engine2', ['ngRoute', 'ngSanitize', 'ngAnimate', 'ngCookies', 'm
360
295
  if elem[0].type in ['text', 'password']
361
296
  elem.on 'keypress', (ev) ->
362
297
  scope.$apply ->
363
- # scope.action.panel_menu_save() if ev.keyCode == 13 # && elem[0].type != 'textarea'
364
- scope.$emit "return_pressed" if ev.keyCode == 13 # && elem[0].type != 'textarea'
298
+ scope.action.panel_menu_default_action?() if ev.keyCode == 13
299
+
365
300
  ev.stopPropagation()
366
301
 
367
302
  if info.filter
@@ -380,7 +315,7 @@ angular.module('Engine2', ['ngRoute', 'ngSanitize', 'ngAnimate', 'ngCookies', 'm
380
315
  link: (scope, elem, attrs, controller) ->
381
316
  name = attrs.e2Field || scope.f
382
317
  meta = scope.action.meta
383
- info = meta.info[name]
318
+ info = meta.fields[name]
384
319
  if info.filter
385
320
  filter = $filter(info.filter)
386
321
  controller.$parsers.push (value) ->
@@ -397,37 +332,43 @@ angular.module('Engine2', ['ngRoute', 'ngSanitize', 'ngAnimate', 'ngCookies', 'm
397
332
  scope: false
398
333
  link: (scope, elem, attrs) ->
399
334
  name = $parse(attrs.template)(scope)
400
- $http.get(name, cache: $templateCache).success (body) ->
335
+ $http.get(name, cache: $templateCache).then (response) ->
401
336
  # elem.html($compile(body)(scope))
402
337
  # elem.replaceWith($compile(body)(scope))
403
338
  elem.empty()
404
- elem.after($compile(body)(scope))
339
+ elem.after($compile(response.data)(scope))
405
340
 
406
341
  .directive 'e2TableBody', ($parse, $compile) ->
407
- table_tmpl = _.template("<thead><tr>{{thead}}</tr></thead><tbody>{{tbody}}</tbody>")
342
+ table_tmpl = _.template("<thead><tr>{{thead}}</tr></thead><tbody {{tbody_attrs}}>{{tbody}}</tbody>")
408
343
  scope: false
409
344
  restrict: 'A'
410
345
  link: (scope, elem, attrs) ->
346
+ table_scope = null
411
347
  scope.$on 'render_table', (a, ev) ->
412
348
  # ev.stopPropagation()
413
- action = scope.action
349
+ table_scope.$destroy() if table_scope
350
+ table_scope = scope.$new(false)
351
+
352
+ action = table_scope.action
414
353
  meta = action.meta
354
+ draggable = meta.draggable
415
355
  position = meta.menus.item_menu.properties.position ? 0
416
- right_style = if position >= meta.fields.length then "style=\"text-align: right\"" else ""
356
+ right_style = if position >= meta.field_list.length then "style=\"text-align: right\"" else ""
417
357
 
418
358
  thead = ""
419
- fields = meta.fields.slice()
359
+ fields = meta.field_list.slice()
420
360
  fields.splice(position, 0, null)
421
361
  _.each fields, (f) ->
422
362
  if f
423
- info = meta.info[f]
363
+ info = meta.fields[f]
424
364
  thead += "<th>"
425
365
  title = if info.title then "title=\"#{info.title}\"" else ""
426
366
  if info.sort
427
367
  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>"
368
+ thead += if action.ui.order == f
369
+ " <span class=\"fa fa-arrow-#{if action.ui.asc then "up" else "down"}\"></span>"
370
+ else
371
+ " <span class=\"fa fa-sort\"></span>"
431
372
  else
432
373
  thead += "<span #{title}>#{info.loc}</span>"
433
374
  thead += "</th>"
@@ -438,25 +379,27 @@ angular.module('Engine2', ['ngRoute', 'ngSanitize', 'ngAnimate', 'ngCookies', 'm
438
379
  _.each action.entries, (e, i) ->
439
380
  tbody += if action.selection then "<tr ng-class=\"action.selected_class(#{i})\" class=\"tr_hover\" ng-click=\"action.select(#{i}, $event)\">" else
440
381
  row_cls = e.$row_info?.class
441
- if row_cls then "<tr class=\"#{row_cls}\">" else "<tr>"
382
+ tr_attrs = if draggable then "dnd-draggable=\"action.entries[#{i}]\" dnd-dragstart=\"action.entry_moved(#{i})\"" else ''
383
+ if row_cls then "<tr class=\"#{row_cls}\" #{tr_attrs}>" else "<tr #{tr_attrs}>"
442
384
  _.each fields, (f) ->
443
385
  if f
444
- tbody += if col_cls = meta.info[f].column_class then "<td class=\"#{col_cls}\">" else "<td>"
386
+ tbody += if col_cls = meta.fields[f].column_class then "<td class=\"#{col_cls}\">" else "<td>"
445
387
  tbody += action.list_cell(e, f) ? ''
446
388
  tbody += "</td>"
447
389
  else
448
390
  tbody += "<td #{right_style}><div e2-button-set=\"action.meta.menus.item_menu\" index=\"#{i}\"></div></td>"
449
391
  tbody += "</tr>"
450
392
 
393
+ tbody_attrs = if draggable then 'dnd-list=\"action.entries\" dnd-drop=\"action.entry_dropped(index, external, type)\"' else ''
451
394
  elem.empty()
452
- elem.append($compile(table_tmpl thead: thead, tbody: tbody)(scope))
395
+ elem.append($compile(table_tmpl thead: thead, tbody: tbody, tbody_attrs: tbody_attrs)(table_scope))
453
396
 
454
397
  .directive 'e2Dropdown', ($parse, $dropdown, $timeout, E2Snippets) ->
455
398
  event_num = 0
456
- dropdown_sub_tmpl = _.template("<li class='dropdown-submenu'><a href=''> {{icon}}{{aicon}} {{loc}}</a>{{sub}}</li>")
457
- dropdown_tmpl = _.template("<li {{clazz}} {{show}} {{hide}}> <a href='{{href}}' {{click}}> {{icon}}{{aicon}} {{loc}}</a></li>")
399
+ dropdown_sub_tmpl = _.template("<li class='dropdown-submenu' {{show}} {{hide}}><a href=''> {{icon}} {{loc}}</a>{{sub}}</li>")
400
+ dropdown_tmpl = _.template("<li {{clazz}} {{show}} {{hide}} {{active}}> <a {{href}} {{click}}> {{icon}} {{loc}}</a></li>")
458
401
 
459
- render = (menu, level) ->
402
+ render = (menu, nav) ->
460
403
  out = menu.map (m) ->
461
404
  switch
462
405
  when m.divider
@@ -464,18 +407,19 @@ angular.module('Engine2', ['ngRoute', 'ngSanitize', 'ngAnimate', 'ngCookies', 'm
464
407
  when m.menu
465
408
  dropdown_sub_tmpl
466
409
  icon: m.menu.icon && E2Snippets.icon(m.menu.icon) || ''
467
- aicon: m.menu.aicon && E2Snippets.aicon(m.menu.aicon) || ''
468
410
  loc: m.menu.loc
469
- sub: render(m.menu.entries)
411
+ show: m.menu.show && "ng-show=\"#{m.menu.show}\"" || ''
412
+ hide: m.menu.hide && "ng-hide=\"#{m.menu.hide}\"" || ''
413
+ sub: render(m.menu.entries, nav)
470
414
  else
471
415
  dropdown_tmpl
472
416
  clazz: E2Snippets.make_ng_class(m)
473
417
  show: m.show && "ng-show=\"#{m.show}\"" || ''
474
418
  hide: m.hide && "ng-hide=\"#{m.hide}\"" || ''
475
- href: m.href || ''
419
+ href: m.href && "#{if nav then 'ui-sref' else 'href'}=\"#{m.href}\"" || ''
420
+ active: nav && "ui-sref-active='active'" || ''
476
421
  click: m.click && "ng-click=\"#{m.click}\"" || ''
477
422
  icon: m.icon && E2Snippets.icon(m.icon) || ''
478
- aicon: m.aicon && E2Snippets.aicon(m.aicon) || ''
479
423
  loc: m.loc
480
424
  "<ul class='dropdown-menu'>#{out.join('')}</ul>"
481
425
 
@@ -489,7 +433,7 @@ angular.module('Engine2', ['ngRoute', 'ngSanitize', 'ngAnimate', 'ngCookies', 'm
489
433
  # event.preventDefault()
490
434
  # event.stopPropagation()
491
435
  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
436
+ dropdown = $dropdown(elem, (scope: scope, template: render(menu, attrs.nav?), animation: attrs.animation || 'am-flip-x', prefixEvent: "#{event_num}.tooltip")) # , delay: 1
493
437
  dropdown.$promise.then ->
494
438
  event_hide = scope.$on "#{event_num}.tooltip.hide", (e) ->
495
439
  e.stopPropagation()
@@ -505,8 +449,8 @@ angular.module('Engine2', ['ngRoute', 'ngSanitize', 'ngAnimate', 'ngCookies', 'm
505
449
  elem.on "mousedown", hook
506
450
 
507
451
  .directive 'e2ButtonSet', ($parse, $compile, E2Snippets) ->
508
- button_set_tmpl = _.template("<div class='btn btn-default' {{clazz}} {{click}} {{show}} {{hide}} {{title}}> {{icon}}{{aicon}} {{loc}}</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>")
452
+ button_set_tmpl = _.template("<div class='btn btn-default' {{clazz}} {{click}} {{show}} {{hide}} {{title}}> {{icon}} {{loc}}</div>")
453
+ button_set_arr_tmpl = _.template("<div class='btn btn-default' e2-dropdown='{{dropdown}}' data-animation='{{animation}}'>{{icon}}<span class='caret'></span></div>")
510
454
  scope: true # because $index
511
455
  link: (scope, elem, attrs) ->
512
456
  menu = $parse(attrs.e2ButtonSet)(scope)
@@ -523,7 +467,6 @@ angular.module('Engine2', ['ngRoute', 'ngSanitize', 'ngAnimate', 'ngCookies', 'm
523
467
  dropdown: "#{attrs.e2ButtonSet}.entries[#{i}].menu.entries"
524
468
  animation: animation
525
469
  icon: m.menu.icon && "#{E2Snippets.icon(m.menu.icon)}&nbsp;" || ''
526
- aicon: m.menu.aicon && "#{E2Snippets.aicon(m.menu.aicon)}&nbsp;" || ''
527
470
  else if m.divider
528
471
  else
529
472
  out += button_set_tmpl
@@ -532,21 +475,20 @@ angular.module('Engine2', ['ngRoute', 'ngSanitize', 'ngAnimate', 'ngCookies', 'm
532
475
  show: m.show && "ng-show=\"#{m.show}\"" || ''
533
476
  hide: m.hide && "ng-hide=\"#{m.hide}\"" || ''
534
477
  icon: m.icon && E2Snippets.icon(m.icon) || ''
535
- aicon: m.aicon && E2Snippets.aicon(m.aicon) || ''
536
478
  loc: !(m.button_loc == false) && m.loc || ''
537
- title: (m.button_loc == false) && "title=\"#{m.loc}\"" || ''
479
+ title: if m.title then "title=\"#{m.title}\"" else ((m.button_loc == false) && "title=\"#{m.loc}\"" || '')
538
480
 
539
481
  if menu.entries.length > brk
540
482
  out += button_set_arr_tmpl
541
483
  dropdown: "#{attrs.e2ButtonSet}.entries.slice(#{brk})"
542
484
  animation: animation
543
485
  icon: ''
544
- aicon: ''
545
486
 
546
487
  out = "<div class='btn-group #{group_class}'>#{out}</div>"
547
488
  out = $compile(angular.element(out))(scope)
548
489
  if attrs.index && !scope.$index?
549
490
  scope.$index = attrs.index | 0
491
+ scope.$entry = scope.action.entries[scope.$index]
550
492
  # scope.data = attrs.data
551
493
  elem.after(out) # elem.append(out) # elem.replaceWith(out)
552
494
 
@@ -584,27 +526,35 @@ angular.module('Engine2', ['ngRoute', 'ngSanitize', 'ngAnimate', 'ngCookies', 'm
584
526
  when "decimal_date"
585
527
  match = value.match(/^(\d{4}|\d{2})(\d{2})(\d{2})$/)
586
528
  if match then match.slice(1, 4).join('-') else value
587
- else value
529
+ else
530
+ match = value.match(/(.*)(?:\s[-+]\d+)$/)
531
+ if match then match[1] else value
588
532
 
589
533
  scope: true
590
534
  require: 'ngModel'
591
535
  link: (scope, element, attr, controller) ->
592
536
  action = scope.action
593
537
  mode = attr.e2Datepicker
538
+ has_mode = !_.isEmpty(mode)
594
539
  field = scope.other_date ? scope.other_time ? scope.f
595
- info = action.meta.info[field]
540
+ info = action.meta.fields[field]
596
541
 
597
542
  if action.query
598
- scope.value[mode] = parse(action.query.search[scope.f][mode], info)
599
- scope.$on "search_reset", -> scope.value[mode] = null
543
+ f = action.query.search[scope.f]
544
+ if has_mode
545
+ scope.value[mode] = parse(f[mode], info)
546
+ scope.$on "search_reset", -> scope.value[mode] = null
547
+ else
548
+ scope.value.at = parse(f, info)
549
+ scope.$on "search_reset", -> scope.value.at = null
600
550
  else
601
551
  value = parse(action.record[field], info)
602
- if mode then scope.value[mode] = value else scope.value = value
552
+ if has_mode then scope.value[mode] = value else scope.value = value
603
553
 
604
554
  scope.$watch attr.ngModel, (model, o) -> if model != o
605
555
  date = format(model, attr.e2ModelFormat)
606
556
  if action.query
607
- action.query.search[scope.f][mode] = date
557
+ if has_mode then action.query.search[scope.f][mode] = date else action.query.search[scope.f] = date
608
558
  scope.action.search_field_change(scope.f) if date?
609
559
  else
610
560
  action.record[field] = date