engine2 1.0.5 → 1.0.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/app/actions.coffee +93 -58
- data/app/app.css +12 -0
- data/app/engine2.coffee +42 -24
- data/conf/message.yaml +1 -0
- data/conf/message_pl.yaml +1 -0
- data/config.coffee +2 -2
- data/engine2.gemspec +1 -1
- data/lib/engine2/action.rb +130 -126
- data/lib/engine2/action/array.rb +4 -4
- data/lib/engine2/action/decode.rb +13 -9
- data/lib/engine2/action/infra.rb +3 -3
- data/lib/engine2/action/list.rb +17 -10
- data/lib/engine2/action_node.rb +1 -2
- data/lib/engine2/core.rb +35 -7
- data/lib/engine2/model.rb +64 -15
- data/lib/engine2/post_bootstrap.rb +1 -1
- data/lib/engine2/pre_bootstrap.rb +10 -0
- data/lib/engine2/scheme.rb +2 -2
- data/lib/engine2/templates.rb +8 -0
- data/lib/engine2/type_info.rb +37 -15
- data/lib/engine2/version.rb +1 -1
- data/package.json +8 -5
- data/views/fields/blob.slim +1 -1
- data/views/fields/bs_select.slim +2 -2
- data/views/fields/bsselect_picker.slim +4 -4
- data/views/fields/bsselect_picker_opt.slim +5 -5
- data/views/fields/checkbox.slim +4 -4
- data/views/fields/checkbox_buttons.slim +3 -3
- data/views/fields/checkbox_buttons_opt.slim +3 -3
- data/views/fields/currency.slim +2 -2
- data/views/fields/date.slim +4 -4
- data/views/fields/date_range.slim +9 -9
- data/views/fields/date_time.slim +9 -9
- data/views/fields/datetime.slim +8 -8
- data/views/fields/decimal.slim +1 -1
- data/views/fields/decimal_date.slim +3 -3
- data/views/fields/decimal_time.slim +3 -3
- data/views/fields/email.slim +3 -3
- data/views/fields/file_store.slim +4 -4
- data/views/fields/input_text.slim +4 -4
- data/views/fields/integer.slim +1 -1
- data/views/fields/list_bsmselect.slim +20 -0
- data/views/fields/list_bsselect.slim +5 -5
- data/views/fields/list_bsselect_opt.slim +6 -6
- data/views/fields/list_buttons.slim +1 -1
- data/views/fields/list_buttons_opt.slim +2 -2
- data/views/fields/list_select.slim +4 -4
- data/views/fields/list_select_opt.slim +5 -5
- data/views/fields/password.slim +4 -4
- data/views/fields/radio_checkbox.slim +3 -3
- data/views/fields/scaffold.slim +1 -1
- data/views/fields/scaffold_picker.slim +5 -5
- data/views/fields/select_picker.slim +3 -3
- data/views/fields/select_picker_opt.slim +4 -4
- data/views/fields/text_area.slim +3 -3
- data/views/fields/time.slim +5 -4
- data/views/fields/typeahead_picker.slim +5 -5
- data/views/scaffold/fields.slim +4 -4
- data/views/scaffold/form.slim +1 -1
- data/views/scaffold/form_collapse.slim +4 -3
- data/views/scaffold/form_tabs.slim +3 -2
- data/views/scaffold/search.slim +2 -2
- data/views/scaffold/search_collapse.slim +6 -5
- data/views/scaffold/search_tabs.slim +4 -3
- data/views/scaffold/view.slim +2 -2
- data/views/scaffold/view_collapse.slim +5 -4
- data/views/scaffold/view_tabs.slim +4 -3
- data/views/search_fields/bsmselect_picker.slim +4 -4
- data/views/search_fields/bsselect_picker.slim +4 -4
- data/views/search_fields/checkbox.slim +3 -3
- data/views/search_fields/checkbox2.slim +5 -5
- data/views/search_fields/checkbox_buttons.slim +3 -3
- data/views/search_fields/date_range.slim +8 -8
- data/views/search_fields/decimal_date_range.slim +5 -5
- data/views/search_fields/input_text.slim +2 -2
- data/views/search_fields/integer.slim +1 -1
- data/views/search_fields/integer_range.slim +2 -2
- data/views/search_fields/list_bsmselect.slim +4 -4
- data/views/search_fields/list_bsselect.slim +4 -4
- data/views/search_fields/list_buttons.slim +2 -2
- data/views/search_fields/list_select.slim +3 -3
- data/views/search_fields/scaffold_picker.slim +2 -2
- data/views/search_fields/select_picker.slim +3 -3
- data/views/search_fields/typeahead_picker.slim +4 -4
- metadata +6 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 58f23892775f4ae41feaedf7b372844c6524e8088262d51dd7b91e23ccd136c0
|
4
|
+
data.tar.gz: 3a9350c94bee76c210976c9f06edde30bfb3fec3c0ac56941f40889a193d3f7f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 73eb8d90f5701a83888592a80d33874db321756f2b003c3a0359ed2a456d317d38e4c11c307760ed98a708725135b6f03b92d06e2fc2bc2759351ecd8705a939
|
7
|
+
data.tar.gz: a8000d44c3092297f5a50c29ed4e4007e7f1190aefa34cc528b0e7c5375c3d1a0b7bf17321227a159c3585aee49eaf5d13120de7c884fad66e217f255a87d4ae
|
data/app/actions.coffee
CHANGED
@@ -134,7 +134,7 @@ angular.module('Engine2')
|
|
134
134
|
E2.merge(prnt, response.data)
|
135
135
|
|
136
136
|
@post_invoke(params)
|
137
|
-
@
|
137
|
+
@execute_commands() if @meta.execute
|
138
138
|
if @meta.repeat
|
139
139
|
@scope().$on "$destroy", => @destroyed = true
|
140
140
|
$timeout (=> @invoke(params)), @meta.repeat unless @destroyed
|
@@ -203,24 +203,27 @@ angular.module('Engine2')
|
|
203
203
|
ws = $websocket "ws#{l.protocol().slice(4, 5)}://#{l.host()}:#{l.port()}/#{@action_info().action_resource}", undefined, ws_meta.options
|
204
204
|
_.each @globals().ws_methods, (method) =>
|
205
205
|
ws_method_impl = @["ws_#{method}"]
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
ws_method_impl.bind(@)(msg, ws, evt) if ws_method_impl
|
217
|
-
@scope().$eval(ws_method_exec) if ws_method_exec
|
218
|
-
|
219
|
-
ws["on#{_.capitalize(method)}"](ws_method)
|
206
|
+
ws["on#{_.capitalize(method)}"] (evt) =>
|
207
|
+
if method == 'message'
|
208
|
+
msg = JSON.parse(evt.data)
|
209
|
+
if msg.error then @globals().modal().error("WebSocket [#{evt.origin}] - #{msg.error.method}", msg.error.exception) else
|
210
|
+
E2.merge(@, msg)
|
211
|
+
@process_meta()
|
212
|
+
else msg = evt
|
213
|
+
ws_method_impl.bind(@)(msg, ws, evt) if ws_method_impl
|
214
|
+
@execute_commands() if @meta.execute
|
215
|
+
delete @meta.execute
|
220
216
|
|
221
217
|
@web_socket = -> ws
|
222
218
|
@scope().$on "$destroy", -> ws.close()
|
223
219
|
|
220
|
+
execute_commands: ->
|
221
|
+
scope = @scope()
|
222
|
+
_.reduce(@meta.execute, ((pr, cmd) -> pr.then -> scope.$eval(cmd)), $q.when())
|
223
|
+
|
224
|
+
console_log: (o) ->
|
225
|
+
console.log o
|
226
|
+
|
224
227
|
root: class RootAction extends Action
|
225
228
|
initialize: ->
|
226
229
|
super()
|
@@ -268,7 +271,10 @@ angular.module('Engine2')
|
|
268
271
|
_.each response.data.actions, (act, nm) -> act.name = nm
|
269
272
|
tree.actions ?= _.toArray(response.data.actions)
|
270
273
|
@meta_json = response.data.meta
|
271
|
-
|
274
|
+
if @meta_json.state
|
275
|
+
@action_state = {}
|
276
|
+
_.each @meta_json.state, (s) => @action_state[s] = localStorageService.get("#{@globals().application}/#{path.join('/')}/#{s}")
|
277
|
+
@action_state
|
272
278
|
,
|
273
279
|
(err) =>
|
274
280
|
delete @meta_json
|
@@ -318,7 +324,7 @@ angular.module('Engine2')
|
|
318
324
|
|
319
325
|
traverse: (routes) ->
|
320
326
|
menu_tmpl = _.template("<li {{show}} {{hide}} ui-sref-active='active'><a {{href}}>{{icon}} {{loc}}</a></li>")
|
321
|
-
menu_sub_tmpl = _.template("<li {{show}} {{hide}} e2-dropdown='{{dropdown}}'
|
327
|
+
menu_sub_tmpl = _.template("<li {{show}} {{hide}} e2-dropdown='{{dropdown}}' nav='true' data-animation='{{animation}}'><a href='javascript://'>{{icon}} {{loc}}<span class='caret'></span></a></li>")
|
322
328
|
animation = @meta.menus.menu.properties.animation
|
323
329
|
out = routes.map (route, i) ->
|
324
330
|
if route.menu
|
@@ -345,8 +351,8 @@ angular.module('Engine2')
|
|
345
351
|
@ui_state = {}
|
346
352
|
@load_state()
|
347
353
|
|
348
|
-
delete @query.order unless @meta.
|
349
|
-
_.each @query.search, ((sv, sn) => delete @query.search[sn] unless _.includes(@meta.
|
354
|
+
delete @query.order unless @meta.fields[@query.order]?.sort # _.includes(@meta.field_list, @query.order)
|
355
|
+
_.each @query.search, ((sv, sn) => delete @query.search[sn] unless _.includes(@meta.search_field_list, sn))
|
350
356
|
|
351
357
|
destroy: ->
|
352
358
|
@save_state()
|
@@ -355,10 +361,13 @@ angular.module('Engine2')
|
|
355
361
|
process_meta: ->
|
356
362
|
super()
|
357
363
|
meta = @meta
|
358
|
-
meta.
|
364
|
+
meta.field_list = meta.field_list.filter((f) => !meta.fields[f].hidden) if meta.field_list
|
359
365
|
|
360
366
|
# confirm_create, view, confirm_modify, confirm_delete, assocs - implicit
|
361
367
|
|
368
|
+
render_table: ->
|
369
|
+
@scope().$broadcast 'render_table'
|
370
|
+
|
362
371
|
menu_search_toggle: ->
|
363
372
|
@ui_state.search_active = !@ui_state.search_active
|
364
373
|
@save_state() unless @ui_state.search_active
|
@@ -372,7 +381,8 @@ angular.module('Engine2')
|
|
372
381
|
|
373
382
|
menu_select_toggle: ->
|
374
383
|
if @selection then delete @selection else @selection = {}
|
375
|
-
@
|
384
|
+
@render_table()
|
385
|
+
|
376
386
|
|
377
387
|
menu_show_meta: ->
|
378
388
|
@globals().modal().show
|
@@ -394,7 +404,7 @@ angular.module('Engine2')
|
|
394
404
|
E2.id_for(@current_entry(), @meta)
|
395
405
|
|
396
406
|
list_cell: (e, f) ->
|
397
|
-
E2.render_field(e, f, @meta)
|
407
|
+
E2.render_field(e, f, @meta, "<br>")
|
398
408
|
|
399
409
|
invoke: (args = {}) ->
|
400
410
|
@save_state()
|
@@ -404,7 +414,7 @@ angular.module('Engine2')
|
|
404
414
|
super(query).then =>
|
405
415
|
@ui = _.pick @query, ['order', 'asc', 'page']
|
406
416
|
@ui.pagination_active = @ui.page != 0 || @entries.length >= @meta.config.per_page
|
407
|
-
@
|
417
|
+
@render_table()
|
408
418
|
|
409
419
|
load_new: ->
|
410
420
|
@query.page = 0
|
@@ -437,7 +447,7 @@ angular.module('Engine2')
|
|
437
447
|
@load_new()
|
438
448
|
|
439
449
|
search_field_change: (f) ->
|
440
|
-
info = @meta.
|
450
|
+
info = @meta.fields[f]
|
441
451
|
|
442
452
|
@scope().$eval(info.onchange) if info.onchange
|
443
453
|
|
@@ -465,6 +475,17 @@ angular.module('Engine2')
|
|
465
475
|
selected_info: ->
|
466
476
|
@meta.loc.selected + ": " + @selected_size()
|
467
477
|
|
478
|
+
entry_dropped: (moved_to, render = true) ->
|
479
|
+
from = @entries[@moved_from]
|
480
|
+
@entries.splice(@moved_from, 1)
|
481
|
+
@entries.splice((if moved_to > @moved_from then moved_to - 1 else moved_to), 0, from)
|
482
|
+
delete @moved_from
|
483
|
+
@render_table() if render
|
484
|
+
true
|
485
|
+
|
486
|
+
entry_moved: (index) ->
|
487
|
+
@moved_from = index
|
488
|
+
|
468
489
|
bulk_delete: class BulkDeleteAction extends Action
|
469
490
|
invoke: ->
|
470
491
|
super(ids: [_.keys(@parent().parent().selection)]).then =>
|
@@ -472,12 +493,12 @@ angular.module('Engine2')
|
|
472
493
|
|
473
494
|
view: class ViewAction extends Action
|
474
495
|
view_cell: (e, f) ->
|
475
|
-
E2.render_field(e, f, @meta)
|
496
|
+
E2.render_field(e, f, @meta, "<br>")
|
476
497
|
|
477
498
|
form_base_action: class FormBaseAction extends Action
|
478
499
|
initialize: ->
|
479
500
|
super()
|
480
|
-
_.each @meta.
|
501
|
+
_.each @meta.fields, (info, name) =>
|
481
502
|
if info.remote_onchange
|
482
503
|
@scope().$watch (=> @record?[name]), (n) => if n? #if typeof(n) != "undefined"
|
483
504
|
params = value: @record[name]
|
@@ -488,7 +509,7 @@ angular.module('Engine2')
|
|
488
509
|
@scope().$watch (=> @record?[name]), (n) => if n?
|
489
510
|
@scope().$eval(info.onchange)
|
490
511
|
|
491
|
-
if @meta.
|
512
|
+
if @meta.tab_list
|
492
513
|
@scope().$watch "action.activeTab", (tab) => if tab? # && tab >= 0
|
493
514
|
@panel_shown()
|
494
515
|
|
@@ -496,36 +517,37 @@ angular.module('Engine2')
|
|
496
517
|
|
497
518
|
post_invoke: (args) ->
|
498
519
|
super()
|
499
|
-
_.each @meta.
|
520
|
+
_.each @meta.fields, (info, name) =>
|
500
521
|
if _.isString(@record[name]) && !info.dont_strip
|
501
522
|
@record[name] = @record[name].trim()
|
502
523
|
|
503
524
|
panel_menu_default_action: ->
|
504
|
-
_.each @meta.
|
525
|
+
_.each @meta.fields, (v, n) =>
|
505
526
|
@record[n] = null if @record[n] is undefined
|
506
527
|
params = record: @record
|
507
528
|
params.parent_id ?= @parent().query?.parent_id # and StarToManyList ?
|
508
529
|
@invoke_action(@default_action_name, params).then =>
|
509
530
|
dfd = $q.defer()
|
510
531
|
if @errors
|
511
|
-
if @meta.
|
532
|
+
if @meta.tab_list
|
512
533
|
[i, first, curr] = [0, null, false]
|
513
|
-
for
|
514
|
-
|
534
|
+
for tab_name in @meta.tab_list
|
535
|
+
tab = @meta.tabs[tab_name]
|
536
|
+
if _(tab.field_list).find((f) => @errors[f])
|
515
537
|
first = i if not first?
|
516
538
|
act = true if @activeTab == i
|
517
539
|
i++
|
518
540
|
@activeTab = first unless act
|
519
541
|
|
520
542
|
if @activeTab?
|
521
|
-
field = _(@meta.tabs[@activeTab].
|
543
|
+
field = _(@meta.tabs[@meta.tab_list[@activeTab]].field_list).find((f) => @errors[f])
|
522
544
|
# console.log field undefined ?
|
523
545
|
else
|
524
546
|
@activeTab = 0
|
525
547
|
@alert = @errors
|
526
548
|
else
|
527
|
-
field = _(@meta.
|
528
|
-
@alert = @errors if (!field || !@meta.
|
549
|
+
field = _(@meta.field_list).find((f) => @errors[f])
|
550
|
+
@alert = @errors if (!field || !@meta.fields[field] || @meta.fields[field].hidden) # ?
|
529
551
|
$timeout => @scope().$broadcast("focus_field", field)
|
530
552
|
#e.scope.$eval(meta.execute) if meta.execute # ?
|
531
553
|
dfd.resolve()
|
@@ -534,15 +556,15 @@ angular.module('Engine2')
|
|
534
556
|
dfd.promise
|
535
557
|
|
536
558
|
panel_shown: ->
|
537
|
-
field = if @meta.
|
538
|
-
tab = @meta.tabs[@activeTab]
|
559
|
+
field = if @meta.tab_list
|
560
|
+
tab = @meta.tabs[@meta.tab_list[@activeTab]]
|
539
561
|
if @errors
|
540
|
-
_(tab.
|
562
|
+
_(tab.field_list).find((f) => @errors[f]) || _(tab.field_list).find((f) => !@meta.fields[f].hidden)
|
541
563
|
else
|
542
|
-
tab ?= @meta.tabs[0]
|
543
|
-
_(tab.
|
564
|
+
tab ?= @meta.tabs[@meta.tab_list[0]]
|
565
|
+
_(tab.field_list).find((f) => !@meta.fields[f].hidden && !@meta.fields[f].disabled)
|
544
566
|
else
|
545
|
-
_(@meta.
|
567
|
+
_(@meta.field_list).find((f) => !@meta.fields[f].hidden && !@meta.fields[f].disabled)
|
546
568
|
$timeout (=> @scope().$broadcast("focus_field", field)), 300 # hack, on shown ?
|
547
569
|
|
548
570
|
infra: class InfraAction extends Action
|
@@ -552,7 +574,7 @@ angular.module('Engine2')
|
|
552
574
|
if @user
|
553
575
|
@invoke_action('login_form').then (act) =>
|
554
576
|
act.record = name: @user.name
|
555
|
-
act.meta.
|
577
|
+
act.meta.fields.name.disabled = true
|
556
578
|
act.dont_reload_routes = !reload_routes # true
|
557
579
|
else
|
558
580
|
@invoke().then => @set_access(true, true, @user)
|
@@ -591,12 +613,7 @@ angular.module('Engine2')
|
|
591
613
|
modify: class ModifyAction extends FormAction
|
592
614
|
# invoke: (args) ->
|
593
615
|
# super(args).then =>
|
594
|
-
# _.each @meta.primary_fields, (f) => @meta.
|
595
|
-
|
596
|
-
on_change: class OnChangeAction extends Action
|
597
|
-
post_invoke: ->
|
598
|
-
super()
|
599
|
-
@parent().scope().$eval(@meta.execute) if @meta.execute
|
616
|
+
# _.each @meta.primary_fields, (f) => @meta.fields[f].disabled = true
|
600
617
|
|
601
618
|
confirm: class ConfirmAction extends Action
|
602
619
|
panel_menu_approve: ->
|
@@ -607,7 +624,7 @@ angular.module('Engine2')
|
|
607
624
|
initialize: ->
|
608
625
|
super()
|
609
626
|
@decode_field = @scope().f
|
610
|
-
@dinfo = @parentp().meta.
|
627
|
+
@dinfo = @parentp().meta.fields[@decode_field]
|
611
628
|
throw "Primary and foreign key list lengths dont match: [#{@meta.primary_fields}] and [#{@dinfo.fields}]" unless @meta.primary_fields.length == @dinfo.fields.length
|
612
629
|
@scope().$on "search_reset", => @clean()
|
613
630
|
|
@@ -626,7 +643,7 @@ angular.module('Engine2')
|
|
626
643
|
@parentp().search_field_change?(@decode_field)
|
627
644
|
|
628
645
|
decode_description: (entry) ->
|
629
|
-
@meta.decode_fields.map((f) => E2.render_field(entry, f, @meta)).join(@meta.separator)
|
646
|
+
@meta.decode_fields.map((f) => E2.render_field(entry, f, @meta, ', ')).join(@meta.separator)
|
630
647
|
|
631
648
|
parentp: ->
|
632
649
|
@parent().parent()
|
@@ -653,11 +670,11 @@ angular.module('Engine2')
|
|
653
670
|
if @selected.length > 0
|
654
671
|
_.each @dinfo.fields, (fk) -> record[fk] = []
|
655
672
|
_.each @selected, (sel) =>
|
656
|
-
_(@dinfo.fields).zip(E2.split_keys(sel)).each(([fk, k]) => record[fk].push E2.parse_entry(k, @parentp().meta.
|
673
|
+
_(@dinfo.fields).zip(E2.split_keys(sel)).each(([fk, k]) => record[fk].push E2.parse_entry(k, @parentp().meta.fields[fk])).value
|
657
674
|
else @clear_record()
|
658
675
|
else
|
659
676
|
if @selected
|
660
|
-
_(@dinfo.fields).zip(E2.split_keys(@selected)).each(([fk, k]) => record[fk] = E2.parse_entry(k, @parentp().meta.
|
677
|
+
_(@dinfo.fields).zip(E2.split_keys(@selected)).each(([fk, k]) => record[fk] = E2.parse_entry(k, @parentp().meta.fields[fk])).value
|
661
678
|
else @clear_record()
|
662
679
|
|
663
680
|
@parentp().search_field_change?(@decode_field)
|
@@ -679,12 +696,12 @@ angular.module('Engine2')
|
|
679
696
|
if @multiple
|
680
697
|
_.each @dinfo.fields, (fk) => record[fk] = []
|
681
698
|
_.each sel, (rec, ids) =>
|
682
|
-
_(@dinfo.fields).zip(E2.split_keys(ids)).each(([k, v]) => record[k].push E2.parse_entry(v, @parentp().meta.
|
699
|
+
_(@dinfo.fields).zip(E2.split_keys(ids)).each(([k, v]) => record[k].push E2.parse_entry(v, @parentp().meta.fields[k])).value
|
683
700
|
@invoke_decode _.values(sel)
|
684
701
|
delete @decode if _.isEmpty(sel)
|
685
702
|
else
|
686
703
|
[ids, rec] = _(sel).toPairs().head()
|
687
|
-
_(@dinfo.fields).zip(E2.split_keys(ids)).each(([k, v]) => record[k] = E2.parse_entry(v, @parentp().meta.
|
704
|
+
_(@dinfo.fields).zip(E2.split_keys(ids)).each(([k, v]) => record[k] = E2.parse_entry(v, @parentp().meta.fields[k])).value
|
688
705
|
@invoke_decode [rec]
|
689
706
|
@parentp().search_field_change?(@decode_field)
|
690
707
|
|
@@ -694,7 +711,7 @@ angular.module('Engine2')
|
|
694
711
|
else
|
695
712
|
decode_descriptions = (recs) => @decode = recs.map((fields) => @decode_description(fields)).join(' | ')
|
696
713
|
recs = recs.map (r) => if _.isArray(r) then E2.from_id(r, @meta) else r
|
697
|
-
if _(recs).every((r) => _(@meta.
|
714
|
+
if _(recs).every((r) => _(@meta.field_list).every((f) -> r[f]?)) && !@meta.dynamic_meta then decode_descriptions(recs) else
|
698
715
|
@invoke(ids: [recs.map((r) => @meta.primary_fields.map (k) -> r[k])]).then => decode_descriptions(@entries)
|
699
716
|
|
700
717
|
open: ->
|
@@ -720,7 +737,7 @@ angular.module('Engine2')
|
|
720
737
|
|
721
738
|
@scope().$on "$typeahead.select", (e, v, index) =>
|
722
739
|
e.stopPropagation()
|
723
|
-
_(@dinfo.fields).zip(E2.split_keys(@values[index].id)).each(([fk, k]) => @record()[fk] = E2.parse_entry(k, @parentp().meta.
|
740
|
+
_(@dinfo.fields).zip(E2.split_keys(@values[index].id)).each(([fk, k]) => @record()[fk] = E2.parse_entry(k, @parentp().meta.fields[fk])).value
|
724
741
|
@parentp().search_field_change?(@decode_field)
|
725
742
|
|
726
743
|
@scope().$watch "action.decode", (e) => if e?
|
@@ -795,8 +812,23 @@ angular.module('Engine2')
|
|
795
812
|
@query.changes = @changes
|
796
813
|
super()
|
797
814
|
|
798
|
-
|
799
|
-
|
815
|
+
entry_dropped: (moved_to) ->
|
816
|
+
pos_field = @meta.draggable.position_field
|
817
|
+
positions = @entries.map (e) -> e[pos_field]
|
818
|
+
super(moved_to, false)
|
819
|
+
_.each positions, (p, i) =>
|
820
|
+
if @entries[i][pos_field] != p
|
821
|
+
if entry = @current_entry_is('create', @entries[i]) ? @current_entry_is('modify', @entries[i])
|
822
|
+
entry[pos_field] = p
|
823
|
+
else
|
824
|
+
@changes.modify.push(@entries[i])
|
825
|
+
@entries[i][pos_field] = p
|
826
|
+
|
827
|
+
@render_table() # @invoke()
|
828
|
+
true
|
829
|
+
|
830
|
+
current_entry_is: (mode, entry = @current_entry()) ->
|
831
|
+
key = E2.id_for(entry, @meta)
|
800
832
|
_.find(@changes[mode], (e) => E2.id_for(e, @meta) == key)
|
801
833
|
|
802
834
|
star_to_many_field_view: class StarToManyFieldView extends ViewAction
|
@@ -825,6 +857,9 @@ angular.module('Engine2')
|
|
825
857
|
pparent.changes.modify.push @parent().record
|
826
858
|
else # CreateAction
|
827
859
|
_(@parent().meta.primary_fields).each (k) => @parent().record[k] = E2.uuid(5)
|
860
|
+
if draggable = pparent.meta.draggable
|
861
|
+
max = _.maxBy(pparent.entries, (e) -> e.position)
|
862
|
+
@parent().record[draggable.position_field] = if max then max[draggable.position_field] + 1 else 1
|
828
863
|
pparent.changes.create.push @parent().record
|
829
864
|
|
830
865
|
star_to_many_field_delete: class StarToManyFieldDelete extends Action
|
data/app/app.css
CHANGED
data/app/engine2.coffee
CHANGED
@@ -7,10 +7,12 @@ require 'angular-ui-tree'
|
|
7
7
|
require '@uirouter/angularjs'
|
8
8
|
require 'ng-file-upload'
|
9
9
|
require 'angular-load'
|
10
|
+
require 'angular-drag-and-drop-lists'
|
11
|
+
require 'ui-select'
|
10
12
|
|
11
13
|
_.templateSettings.interpolate = /{{([\s\S]+?)}}/g;
|
12
14
|
|
13
|
-
angular.module('Engine2', ['ngSanitize', 'ngAnimate', 'ngCookies', 'mgcrea.ngStrap', 'ngFileUpload', 'ui.tree', 'LocalStorageModule', 'angularLoad', 'ngWebSocket', 'ui.router'
|
15
|
+
angular.module('Engine2', ['ngSanitize', 'ngAnimate', 'ngCookies', 'mgcrea.ngStrap', 'ngFileUpload', 'ui.tree', 'LocalStorageModule', 'angularLoad', 'ngWebSocket', 'ui.router', 'dndLists', 'ui.select'])
|
14
16
|
.config ($httpProvider, $compileProvider, localStorageServiceProvider, $logProvider, $qProvider, $locationProvider, $provide) ->
|
15
17
|
$httpProvider.interceptors.push 'e2HttpInterceptor'
|
16
18
|
$provide.decorator '$httpBackend', ($delegate) ->
|
@@ -29,6 +31,16 @@ angular.module('Engine2', ['ngSanitize', 'ngAnimate', 'ngCookies', 'mgcrea.ngStr
|
|
29
31
|
# $qProvider.errorOnUnhandledRejections(false)
|
30
32
|
# $locationProvider.hashPrefix('')
|
31
33
|
# $locationProvider.html5Mode(false)
|
34
|
+
$provide.decorator 'ngModelDirective', ($delegate) ->
|
35
|
+
directive = $delegate[0]
|
36
|
+
compile = directive.compile
|
37
|
+
directive.compile = (elem, attrs, trans) ->
|
38
|
+
comp = compile(elem, attrs, trans)
|
39
|
+
pre: comp.pre
|
40
|
+
post: (scope, element, attr, ctrls) ->
|
41
|
+
ctrls[0].$parsers.push (vw) -> if vw == "" then null else vw
|
42
|
+
comp.post(scope, element, attr, ctrls)
|
43
|
+
$delegate
|
32
44
|
|
33
45
|
.factory 'PushJS', -> require 'push.js'
|
34
46
|
.factory 'MetaCache', ($cacheFactory) -> $cacheFactory('MetaCache')
|
@@ -212,11 +224,14 @@ angular.module('Engine2', ['ngSanitize', 'ngAnimate', 'ngCookies', 'mgcrea.ngStr
|
|
212
224
|
when render.true_value then E2Snippets.boolean_true_value
|
213
225
|
when render.false_value then E2Snippets.boolean_false_value
|
214
226
|
else "?"
|
215
|
-
list_select: (value, render) ->
|
216
|
-
render.list_hash ||= render.
|
217
|
-
render.
|
227
|
+
list_select: (value, render, separator) ->
|
228
|
+
render.list_hash ||= render.values.reduce(((h, [a, b]) -> h[a] = b; h), {})
|
229
|
+
if render.multiselect && _.isArray(value)
|
230
|
+
value.map((v) -> render.list_hash[v] ? ":#{value}:").join(separator)
|
231
|
+
else
|
232
|
+
render.list_hash[value] ? ":#{value}:"
|
218
233
|
datetime: (value, render) ->
|
219
|
-
value.split('\.')[0]
|
234
|
+
value.split('\.')[0].split(' ', 2).join(' ')
|
220
235
|
# $dateFormatter.formatDate(value, "yyyy-MM-dd", $dateFormatter.getDefaultLocale())
|
221
236
|
integer: (value, render) -> # ?
|
222
237
|
value.toString()
|
@@ -231,12 +246,12 @@ angular.module('Engine2', ['ngSanitize', 'ngAnimate', 'ngCookies', 'mgcrea.ngStr
|
|
231
246
|
value.toString()
|
232
247
|
|
233
248
|
|
234
|
-
render_field: (entry, name, meta) ->
|
249
|
+
render_field: (entry, name, meta, separator) ->
|
235
250
|
value = entry[name]
|
236
|
-
if value? && info = meta.
|
251
|
+
if value? && info = meta.fields
|
237
252
|
f_info = info[name]
|
238
253
|
if f_info? && type = f_info.type
|
239
|
-
@renderers[type](value, f_info.render)
|
254
|
+
@renderers[type](value, f_info.render, separator)
|
240
255
|
else
|
241
256
|
if f_info?.escape == false then value else
|
242
257
|
(value + "").replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">")
|
@@ -260,7 +275,7 @@ angular.module('Engine2', ['ngSanitize', 'ngAnimate', 'ngCookies', 'mgcrea.ngStr
|
|
260
275
|
|
261
276
|
name = attrs.e2Field || scope.f
|
262
277
|
meta = scope.action.meta
|
263
|
-
info = meta.
|
278
|
+
info = meta.fields[name]
|
264
279
|
scope.$on "focus_field", (event, n, mode) ->
|
265
280
|
if n == name
|
266
281
|
elem[0].focus()
|
@@ -293,7 +308,7 @@ angular.module('Engine2', ['ngSanitize', 'ngAnimate', 'ngCookies', 'mgcrea.ngStr
|
|
293
308
|
link: (scope, elem, attrs, controller) ->
|
294
309
|
name = attrs.e2Field || scope.f
|
295
310
|
meta = scope.action.meta
|
296
|
-
info = meta.
|
311
|
+
info = meta.fields[name]
|
297
312
|
if info.filter
|
298
313
|
filter = $filter(info.filter)
|
299
314
|
controller.$parsers.push (value) ->
|
@@ -317,7 +332,7 @@ angular.module('Engine2', ['ngSanitize', 'ngAnimate', 'ngCookies', 'mgcrea.ngStr
|
|
317
332
|
elem.after($compile(response.data)(scope))
|
318
333
|
|
319
334
|
.directive 'e2TableBody', ($parse, $compile) ->
|
320
|
-
table_tmpl = _.template("<thead><tr>{{thead}}</tr></thead><tbody>{{tbody}}</tbody>")
|
335
|
+
table_tmpl = _.template("<thead><tr>{{thead}}</tr></thead><tbody {{tbody_attrs}}>{{tbody}}</tbody>")
|
321
336
|
scope: false
|
322
337
|
restrict: 'A'
|
323
338
|
link: (scope, elem, attrs) ->
|
@@ -325,15 +340,16 @@ angular.module('Engine2', ['ngSanitize', 'ngAnimate', 'ngCookies', 'mgcrea.ngStr
|
|
325
340
|
# ev.stopPropagation()
|
326
341
|
action = scope.action
|
327
342
|
meta = action.meta
|
343
|
+
draggable = meta.draggable
|
328
344
|
position = meta.menus.item_menu.properties.position ? 0
|
329
|
-
right_style = if position >= meta.
|
345
|
+
right_style = if position >= meta.field_list.length then "style=\"text-align: right\"" else ""
|
330
346
|
|
331
347
|
thead = ""
|
332
|
-
fields = meta.
|
348
|
+
fields = meta.field_list.slice()
|
333
349
|
fields.splice(position, 0, null)
|
334
350
|
_.each fields, (f) ->
|
335
351
|
if f
|
336
|
-
info = meta.
|
352
|
+
info = meta.fields[f]
|
337
353
|
thead += "<th>"
|
338
354
|
title = if info.title then "title=\"#{info.title}\"" else ""
|
339
355
|
if info.sort
|
@@ -351,25 +367,27 @@ angular.module('Engine2', ['ngSanitize', 'ngAnimate', 'ngCookies', 'mgcrea.ngStr
|
|
351
367
|
_.each action.entries, (e, i) ->
|
352
368
|
tbody += if action.selection then "<tr ng-class=\"action.selected_class(#{i})\" class=\"tr_hover\" ng-click=\"action.select(#{i}, $event)\">" else
|
353
369
|
row_cls = e.$row_info?.class
|
354
|
-
if
|
370
|
+
tr_attrs = if draggable then "dnd-draggable=\"action.entries[#{i}]\" dnd-dragstart=\"action.entry_moved(#{i})\"" else ''
|
371
|
+
if row_cls then "<tr class=\"#{row_cls}\" #{tr_attrs}>" else "<tr #{tr_attrs}>"
|
355
372
|
_.each fields, (f) ->
|
356
373
|
if f
|
357
|
-
tbody += if col_cls = meta.
|
374
|
+
tbody += if col_cls = meta.fields[f].column_class then "<td class=\"#{col_cls}\">" else "<td>"
|
358
375
|
tbody += action.list_cell(e, f) ? ''
|
359
376
|
tbody += "</td>"
|
360
377
|
else
|
361
378
|
tbody += "<td #{right_style}><div e2-button-set=\"action.meta.menus.item_menu\" index=\"#{i}\"></div></td>"
|
362
379
|
tbody += "</tr>"
|
363
380
|
|
381
|
+
tbody_attrs = if draggable then 'dnd-list=\"action.entries\" dnd-drop=\"action.entry_dropped(index, external, type)\"' else ''
|
364
382
|
elem.empty()
|
365
|
-
elem.append($compile(table_tmpl thead: thead, tbody: tbody)(scope))
|
383
|
+
elem.append($compile(table_tmpl thead: thead, tbody: tbody, tbody_attrs: tbody_attrs)(scope))
|
366
384
|
|
367
385
|
.directive 'e2Dropdown', ($parse, $dropdown, $timeout, E2Snippets) ->
|
368
386
|
event_num = 0
|
369
387
|
dropdown_sub_tmpl = _.template("<li class='dropdown-submenu' {{show}} {{hide}}><a href=''> {{icon}} {{loc}}</a>{{sub}}</li>")
|
370
|
-
dropdown_tmpl = _.template("<li {{clazz}} {{show}} {{hide}}> <a {{href}} {{click}}> {{icon}} {{loc}}</a></li>")
|
388
|
+
dropdown_tmpl = _.template("<li {{clazz}} {{show}} {{hide}} {{active}}> <a {{href}} {{click}}> {{icon}} {{loc}}</a></li>")
|
371
389
|
|
372
|
-
render = (menu,
|
390
|
+
render = (menu, nav) ->
|
373
391
|
out = menu.map (m) ->
|
374
392
|
switch
|
375
393
|
when m.divider
|
@@ -380,13 +398,14 @@ angular.module('Engine2', ['ngSanitize', 'ngAnimate', 'ngCookies', 'mgcrea.ngStr
|
|
380
398
|
loc: m.menu.loc
|
381
399
|
show: m.menu.show && "ng-show=\"#{m.menu.show}\"" || ''
|
382
400
|
hide: m.menu.hide && "ng-hide=\"#{m.menu.hide}\"" || ''
|
383
|
-
sub: render(m.menu.entries)
|
401
|
+
sub: render(m.menu.entries, nav)
|
384
402
|
else
|
385
403
|
dropdown_tmpl
|
386
404
|
clazz: E2Snippets.make_ng_class(m)
|
387
405
|
show: m.show && "ng-show=\"#{m.show}\"" || ''
|
388
406
|
hide: m.hide && "ng-hide=\"#{m.hide}\"" || ''
|
389
|
-
href: m.href && "#{href}=\"#{m.href}\"" || ''
|
407
|
+
href: m.href && "#{if nav then 'ui-sref' else 'href'}=\"#{m.href}\"" || ''
|
408
|
+
active: nav && "ui-sref-active='active'" || ''
|
390
409
|
click: m.click && "ng-click=\"#{m.click}\"" || ''
|
391
410
|
icon: m.icon && E2Snippets.icon(m.icon) || ''
|
392
411
|
loc: m.loc
|
@@ -402,8 +421,7 @@ angular.module('Engine2', ['ngSanitize', 'ngAnimate', 'ngCookies', 'mgcrea.ngStr
|
|
402
421
|
# event.preventDefault()
|
403
422
|
# event.stopPropagation()
|
404
423
|
menu = $parse(attrs.e2Dropdown)(scope)
|
405
|
-
|
406
|
-
dropdown = $dropdown(elem, (scope: scope, template: render(menu, href), animation: attrs.animation || 'am-flip-x', prefixEvent: "#{event_num}.tooltip")) # , delay: 1
|
424
|
+
dropdown = $dropdown(elem, (scope: scope, template: render(menu, attrs.nav?), animation: attrs.animation || 'am-flip-x', prefixEvent: "#{event_num}.tooltip")) # , delay: 1
|
407
425
|
dropdown.$promise.then ->
|
408
426
|
event_hide = scope.$on "#{event_num}.tooltip.hide", (e) ->
|
409
427
|
e.stopPropagation()
|
@@ -504,7 +522,7 @@ angular.module('Engine2', ['ngSanitize', 'ngAnimate', 'ngCookies', 'mgcrea.ngStr
|
|
504
522
|
action = scope.action
|
505
523
|
mode = attr.e2Datepicker
|
506
524
|
field = scope.other_date ? scope.other_time ? scope.f
|
507
|
-
info = action.meta.
|
525
|
+
info = action.meta.fields[field]
|
508
526
|
|
509
527
|
if action.query
|
510
528
|
scope.value[mode] = parse(action.query.search[scope.f][mode], info)
|