engine2 1.0.4 → 1.0.9

Sign up to get free protection for your applications and to get access to all the features.
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