engine2 1.0.5 → 1.0.6
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.
- 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)
|