|
@@ -174,10 +174,11 @@
|
|
|
<div class="col-5 pr-0 pl-3 border-left tree-column">
|
|
|
<div class="d-flex align-items-baseline mb-2">
|
|
|
<h6 class="font-weight-bold m-0">{{$statTree->name}}</h6>
|
|
|
+ <span class="text-danger d-none if-changed ml-2 text-sm">(modified *)</span>
|
|
|
<a href="#" id="refresh-counts" class="ml-3">Refresh Counts</a>
|
|
|
<a href="#" class="tree-expand-all ml-3" title="Expand All"><i class="fa fa-angle-double-down text-secondary"></i></a>
|
|
|
<a href="#" class="tree-collapse-all ml-2" title="Collapse All"><i class="fa fa-angle-double-up text-secondary"></i></a>
|
|
|
- <div class="d-none if-changed ml-auto mr-2">
|
|
|
+ <div class="ml-auto mr-2 d-none if-changed">
|
|
|
<a href="#" class="btn btn-sm btn-primary text-white" id="btn-save-tree">Save</a>
|
|
|
<a href="#" class="ml-2 btn btn-sm btn-default border text-dark" onclick="return fastReload()">Reset</a>
|
|
|
</div>
|
|
@@ -186,26 +187,8 @@
|
|
|
@if(!$statTree->rootLines || !count($statTree->rootLines))
|
|
|
<p class="text-sm text-secondary font-italic">Drag clauses from the left and drop it above to begin.</p>
|
|
|
@endif
|
|
|
-
|
|
|
- <!-- hidden moes invoked due to context actions -->
|
|
|
- <div class="border mb-3 p-2 position-absolute" style="left: -10000px; top: -10000px;">
|
|
|
- <div class="d-inline-flex align-items-baseline">
|
|
|
-
|
|
|
- <!-- remove line -->
|
|
|
- <div moe relative center id="remove-line-moe">
|
|
|
- <a href="#" start show><i class="text-sm fa fa-trash-alt on-hover-opaque text-danger"></i></a>
|
|
|
- <form url="{{ route("practice-management.api.statTreeLine.remove") }}" center hook="reloadStatTree">
|
|
|
- @csrf
|
|
|
- <input type="hidden" name="uid">
|
|
|
- <p>Are you sure?</p>
|
|
|
- <div class="d-flex align-items-center">
|
|
|
- <button class="btn btn-sm btn-danger mr-2" type="button" submit>Remove</button>
|
|
|
- <button class="btn btn-sm btn-default mr-2 border" type="button" cancel>Cancel</button>
|
|
|
- </div>
|
|
|
- </form>
|
|
|
- </div>
|
|
|
-
|
|
|
- </div>
|
|
|
+ <div class="d-flex align-items-baseline">
|
|
|
+ <a href="#" class="log-tree mr-2">Log</a>
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
@@ -219,7 +202,7 @@
|
|
|
</div>
|
|
|
<div class="d-flex align-items-baseline mb-2">
|
|
|
<h6 class="font-weight-bold m-0 text-secondary">Argument Values</h6>
|
|
|
- <a href="#" class="ml-3 text-sm" onclick="$('.parent-arg').toggle(); return false;">Toggle Parent Clause Args</a>
|
|
|
+ <!--<a href="#" class="ml-3 text-sm" onclick="$('.parent-arg').toggle(); return false;">Toggle Parent Clause Args</a>-->
|
|
|
</div>
|
|
|
<div>
|
|
|
<table class="table table-sm table-bordered table-striped">
|
|
@@ -281,8 +264,8 @@
|
|
|
let moe = $(_id);
|
|
|
moe.find('input[name], select[name]').each(function() {
|
|
|
let name = $(this).attr('name');
|
|
|
- if(!!_node.original.system[name]) {
|
|
|
- $(this).val(!!_node.original.system[name] ? _node.original.system[name] : '');
|
|
|
+ if(!!_node.data[name]) {
|
|
|
+ $(this).val(!!_node.data[name] ? _node.data[name] : '');
|
|
|
}
|
|
|
});
|
|
|
moe.find('a[start]').trigger('click');
|
|
@@ -312,14 +295,13 @@
|
|
|
},
|
|
|
"dnd": {
|
|
|
"is_draggable": function(_node, _e) {
|
|
|
- return _node[0].original.system.type === 'clause';
|
|
|
+ return _node[0].data.type === 'clause';
|
|
|
}
|
|
|
},
|
|
|
"contextmenu": {
|
|
|
show_at_node: false,
|
|
|
items: function (node) {
|
|
|
- console.log('ALIX',node.original.system)
|
|
|
- if(node.original.system.type === 'clause') { // clause
|
|
|
+ if(node.data.type === 'clause') { // clause
|
|
|
return {
|
|
|
"edit": {
|
|
|
"label": "<span class='text-sm'>Edit Clause</span>",
|
|
@@ -341,7 +323,7 @@
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
- else if(node.original.system.type === 'clause_arg') { // clause
|
|
|
+ else if(node.data.type === 'clause_arg') { // clause
|
|
|
return {
|
|
|
"edit": {
|
|
|
"label": "<span class='text-sm'>Edit Arg</span>",
|
|
@@ -373,6 +355,18 @@
|
|
|
// stat tree
|
|
|
let StatTree = {
|
|
|
el: $('#stat-tree-view-{{$statTree->id}}'),
|
|
|
+ changed: false,
|
|
|
+
|
|
|
+ setDirty: function(_changed = true) {
|
|
|
+ this.changed = _changed;
|
|
|
+ if(_changed) {
|
|
|
+ $('.if-changed').removeClass('d-none');
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ $('.if-changed').addClass('d-none');
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
load: function() {
|
|
|
|
|
|
// destroy if existing
|
|
@@ -386,10 +380,8 @@
|
|
|
|
|
|
// init tree with data
|
|
|
this.el
|
|
|
- .on('move_node.jstree', function(node, original) { StatTree.dropped(node, original); })
|
|
|
- .on('copy_node.jstree', function() { StatTree.dropped.apply(StatTree, arguments); })
|
|
|
- // .on('move_node.jstree', function() { StatTree.save(); })
|
|
|
- // .on('copy_node.jstree', function() { StatTree.save(); })
|
|
|
+ .on('move_node.jstree', (_e, _data) => { StatTree.dropped(_e, _data); })
|
|
|
+ .on('copy_node.jstree', (_e, _data) => { StatTree.dropped(_e, _data); })
|
|
|
.on('select_node.jstree', () => { StatTree.onSelected(); })
|
|
|
.on('deselect_node.jstree', () => { StatTree.onDeselected(); })
|
|
|
.jstree({
|
|
@@ -401,22 +393,21 @@
|
|
|
},
|
|
|
"dnd": {
|
|
|
"is_draggable": function(_node, _e) {
|
|
|
- return _node[0].original.system && _node[0].original.system.type === 'stat_tree_line';
|
|
|
+ return _node[0].data && _node[0].data.type === 'stat_tree_line';
|
|
|
}
|
|
|
},
|
|
|
"contextmenu": {
|
|
|
show_at_node: false,
|
|
|
items: function (node) {
|
|
|
- console.log('ALIX',node);
|
|
|
- if(node.original.system.type === 'stat_tree_line') { // stat_tree_line
|
|
|
+ if(node.data.type === 'stat_tree_line') { // stat_tree_line
|
|
|
return {
|
|
|
|
|
|
"data": {
|
|
|
"label": "<span class='text-sm'>View Data</span>",
|
|
|
"action": function (obj) {
|
|
|
- openDynamicStagPopup('/practice-management/stat-tree-lines/view-data/' + node.original.system.uid,
|
|
|
+ openDynamicStagPopup('/practice-management/stat-tree-lines/view-data/' + node.data.uid,
|
|
|
null,
|
|
|
- node.original.system.displayLabel,
|
|
|
+ node.data.displayLabel,
|
|
|
false,
|
|
|
'medium');
|
|
|
},
|
|
@@ -424,7 +415,11 @@
|
|
|
"remove": {
|
|
|
"label": "<span class='text-sm'>Remove Node</span>",
|
|
|
"action": function (obj) {
|
|
|
- fillAndInvokeMoe('#remove-line-moe', node);
|
|
|
+ let selected = StatTree.selectedNode();
|
|
|
+ if(selected) {
|
|
|
+ StatTree.el.jstree(true).delete_node(selected.id);
|
|
|
+ StatTree.setDirty();
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@@ -442,29 +437,95 @@
|
|
|
},
|
|
|
|
|
|
dropped: function(_e, _data) {
|
|
|
- if(_data.original && _data.original.original && _data.original.original.system &&
|
|
|
- _data.original.original.system.type === 'clause') {
|
|
|
- _data.node.original.system = _data.original.original.system;
|
|
|
+
|
|
|
+ if(_data.original && _data.original.data &&
|
|
|
+ _data.original.data.type === 'clause') {
|
|
|
+ _data.node.data = {
|
|
|
+ type: "stat_tree_line",
|
|
|
+ displayLabel: _data.original.data.label,
|
|
|
+ columns: [],
|
|
|
+ clause: {
|
|
|
+ clause_id: _data.original.data.clauseId,
|
|
|
+ clause_label: _data.original.data.label,
|
|
|
+ args: _data.original.data.args
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ // delete args and query children (from the clauses tree)
|
|
|
+ this.el.jstree(true).delete_node(_data.node.children);
|
|
|
+
|
|
|
+ // open new parent to reveal dropped node
|
|
|
+ this.el.jstree(true).open_node(_data.parent);
|
|
|
+
|
|
|
+ // select the new node
|
|
|
+ this.el.jstree(true).deselect_all();
|
|
|
+ this.el.jstree(true).select_node(_data.node.id);
|
|
|
}
|
|
|
- StatTree.save();
|
|
|
+ else if(_e.type === 'copy_node' && _data.original && _data.original.data &&
|
|
|
+ _data.original.data.type === 'stat_tree_line') {
|
|
|
+
|
|
|
+ function recursiveCopyData(src, target) {
|
|
|
+ src = StatTree.el.jstree(true).get_node(src);
|
|
|
+ target = StatTree.el.jstree(true).get_node(target);
|
|
|
+ target.data = JSON.parse(JSON.stringify(src.data));
|
|
|
+ if(src.children.length === target.children.length) {
|
|
|
+ for (let i = 0; i < target.children.length; i++) {
|
|
|
+ recursiveCopyData(src.children[i], target.children[i])
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ console.log('Child count not the same!', src.text, target.text);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ recursiveCopyData(_data.original.id, _data.node.id);
|
|
|
+
|
|
|
+ // open new parent to reveal dropped node
|
|
|
+ this.el.jstree(true).open_node(_data.parent);
|
|
|
+
|
|
|
+ // select the new node
|
|
|
+ this.el.jstree(true).deselect_all();
|
|
|
+ this.el.jstree(true).select_node(_data.node.id);
|
|
|
+ }
|
|
|
+
|
|
|
+ this.setDirty();
|
|
|
},
|
|
|
|
|
|
save: function() {
|
|
|
setTimeout(() => {
|
|
|
- StatTree.payload();
|
|
|
$.post('{{ route("practice-management.api.statTree.replaceAllLinesJSON") }}', {
|
|
|
uid: "{{ $statTree->uid }}",
|
|
|
data: StatTree.payload()
|
|
|
}, function (response) {
|
|
|
if(!hasResponseError(response)) {
|
|
|
+ toastr.success('All changes saved!');
|
|
|
+ StatTree.setDirty(false);
|
|
|
StatTree.load();
|
|
|
- // TODO: saved indicator
|
|
|
}
|
|
|
}, 'json');
|
|
|
StatTree.onSelected();
|
|
|
}, 0);
|
|
|
},
|
|
|
|
|
|
+ log: function() {
|
|
|
+ let raw = this.el.jstree('get_json');
|
|
|
+ for (let i = 0; i < raw.length; i++) {
|
|
|
+ this.logNode(raw[i].id, "");
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ logNode: function(_id, _indent) {
|
|
|
+ let node = this.el.jstree('get_node', _id);
|
|
|
+ let s = [], css = false;
|
|
|
+ if(!node.data) css = true;
|
|
|
+ s.push($('<div/>').html(node.text).text().substr(0, 10) + '...');
|
|
|
+ s.push(node.data ? 'data:' + node.data.type: '%cdata:X');
|
|
|
+ console.log("ALIX: " + _indent + s.join(' '), css ? 'color:red' : '');
|
|
|
+ for (let i = 0; i < node.children.length; i++) {
|
|
|
+ this.logNode(node.children[i], _indent + "\t");
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
payload: function() {
|
|
|
let raw = this.el.jstree('get_json');
|
|
|
let nodes = [];
|
|
@@ -474,32 +535,18 @@
|
|
|
return JSON.stringify(nodes);
|
|
|
},
|
|
|
|
|
|
- nodePayload: function(_id, _parentClauses = null) {
|
|
|
+ nodePayload: function(_id) {
|
|
|
let node = this.el.jstree('get_node', _id);
|
|
|
let payload = {};
|
|
|
- let clauses = _parentClauses ? JSON.parse(JSON.stringify(_parentClauses)) : [];
|
|
|
- if(node.original.system.type === 'clause') {
|
|
|
- clauses.push({
|
|
|
- clause_label: node.original.system.label,
|
|
|
- args: []
|
|
|
- });
|
|
|
+ if(node.data.type === 'stat_tree_line') {
|
|
|
payload = {
|
|
|
- displayLabel: node.original.system.label,
|
|
|
- clauses: clauses,
|
|
|
- columns: [],
|
|
|
- children: [],
|
|
|
- };
|
|
|
- }
|
|
|
- else if(node.original.system.type === 'stat_tree_line') {
|
|
|
- clauses.push(node.original.system.clauses[node.original.system.clauses.length - 1]);
|
|
|
- payload = {
|
|
|
- displayLabel: node.original.system.displayLabel,
|
|
|
- clauses: clauses,
|
|
|
- columns: node.original.system.columns,
|
|
|
+ displayLabel: node.data.displayLabel,
|
|
|
+ clause: node.data.clause,
|
|
|
+ columns: node.data.columns,
|
|
|
};
|
|
|
let children = [];
|
|
|
for (let i = 0; i < node.children.length; i++) {
|
|
|
- children.push(this.nodePayload(node.children[i], clauses));
|
|
|
+ children.push(this.nodePayload(node.children[i]));
|
|
|
}
|
|
|
payload.children = children;
|
|
|
}
|
|
@@ -517,7 +564,7 @@
|
|
|
getSelectedNodeArgs: function() {
|
|
|
let selected = this.selectedNode();
|
|
|
if(selected) {
|
|
|
- return selected.original.system.args;
|
|
|
+ return selected.data.args;
|
|
|
}
|
|
|
return [];
|
|
|
},
|
|
@@ -525,7 +572,7 @@
|
|
|
getSelectedNodeColumns: function() {
|
|
|
let selected = this.selectedNode();
|
|
|
if(selected) {
|
|
|
- return selected.original.system.columns;
|
|
|
+ return selected.data.columns;
|
|
|
}
|
|
|
return [];
|
|
|
},
|
|
@@ -533,7 +580,8 @@
|
|
|
setSelectedNodeColumns: function(columns) {
|
|
|
let selected = this.selectedNode();
|
|
|
if(selected) {
|
|
|
- selected.original.system.columns = columns;
|
|
|
+ selected.data.columns = columns;
|
|
|
+ this.setDirty();
|
|
|
}
|
|
|
return [];
|
|
|
},
|
|
@@ -545,34 +593,32 @@
|
|
|
onSelected: function(_e, _data) {
|
|
|
let selected = this.selectedNode();
|
|
|
|
|
|
- if(!(selected && selected.original && selected.original.system && selected.original.system.type === 'stat_tree_line')) return;
|
|
|
+ if(selected) console.log(selected.data)
|
|
|
|
|
|
- console.log('ALIX',selected.original.system)
|
|
|
+ if(!(selected && selected.data && selected.data.type === 'stat_tree_line')) return;
|
|
|
|
|
|
linePropsColumn.removeClass('d-none');
|
|
|
- linePropsColumn.find('[line-label]').text(selected.original.system.displayLabel);
|
|
|
+ linePropsColumn.find('[line-label]').text(selected.data.displayLabel);
|
|
|
|
|
|
// fill args
|
|
|
let tbody = linePropsColumn.find('[line-args]');
|
|
|
- let clauses = selected.original.system.clauses;
|
|
|
+ let clause = selected.data.clause;
|
|
|
tbody.empty();
|
|
|
- if(clauses && clauses.length) {
|
|
|
- for (let j = 0; j < clauses.length; j++) {
|
|
|
- let edit = j === clauses.length - 1;
|
|
|
- let args = clauses[j].args ? clauses[j].args : [];
|
|
|
- $('<tr/>').addClass(edit ? '' : 'opacity-60 parent-arg').append($('<td/>').attr('colspan', 3).addClass('font-weight-bold text-sm ' + (edit ? '' : 'text-secondary')).text((j+1) + '. ' + clauses[j].clause_label)).appendTo(tbody);
|
|
|
- if(!args.length) {
|
|
|
- $('<tr/>').addClass(edit ? '' : 'opacity-60 parent-arg').append($('<td/>').attr('colspan', 3).addClass('pl-3 text-secondary text-sm').text('No args')).appendTo(tbody);
|
|
|
- }
|
|
|
- else {
|
|
|
- for (let i = 0; i < args.length; i++) {
|
|
|
- $('<tr/>')
|
|
|
- .addClass(edit ? '' : 'opacity-60 parent-arg')
|
|
|
- .append($('<td/>').addClass('pl-3').html(args[i].arg_text + ' <span class="text-secondary text-sm">(' + args[i].field_type + ')</span>'))
|
|
|
- .append($('<td/>').text(args[i].default_value).append(edit ? '<a href="#" class="edit-arg-value ml-2" data-uid="' + args[i].uid + '"><i class="fa fa-edit text-primary text-sm on-hover-opaque"></i></a>': ''))
|
|
|
- .append($('<td/>').text(args[i].access_level).append(edit ? '<a href="#" class="edit-arg-access-level ml-2" data-uid="' + args[i].uid + '"><i class="fa fa-edit text-primary text-sm on-hover-opaque"></i></a>': ''))
|
|
|
- .appendTo(tbody);
|
|
|
- }
|
|
|
+ if(clause) {
|
|
|
+ let edit = true;
|
|
|
+ let args = clause.args ? clause.args : [];
|
|
|
+ // $('<tr/>').addClass(edit ? '' : 'opacity-60 parent-arg').append($('<td/>').attr('colspan', 3).addClass('font-weight-bold text-sm ' + (edit ? '' : 'text-secondary')).text(clause.clause_label)).appendTo(tbody);
|
|
|
+ if(!args.length) {
|
|
|
+ $('<tr/>').addClass(edit ? '' : 'opacity-60 parent-arg').append($('<td/>').attr('colspan', 3).addClass('pl-3 text-secondary text-sm').text('No args')).appendTo(tbody);
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ for (let i = 0; i < args.length; i++) {
|
|
|
+ $('<tr/>')
|
|
|
+ .addClass(edit ? '' : 'opacity-60 parent-arg')
|
|
|
+ .append($('<td/>').addClass('pl-3').html(args[i].arg_text + ' <span class="text-secondary text-sm">(' + args[i].field_type + ')</span>'))
|
|
|
+ .append($('<td/>').text(args[i].default_value).append(edit ? '<a href="#" class="edit-arg-value ml-2" data-uid="' + args[i].uid + '"><i class="fa fa-edit text-primary text-sm on-hover-opaque"></i></a>': ''))
|
|
|
+ .append($('<td/>').text(args[i].access_level).append(edit ? '<a href="#" class="edit-arg-access-level ml-2" data-uid="' + args[i].uid + '"><i class="fa fa-edit text-primary text-sm on-hover-opaque"></i></a>': ''))
|
|
|
+ .appendTo(tbody);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@@ -609,9 +655,10 @@
|
|
|
label: _data.label,
|
|
|
display_key: _data.text
|
|
|
});
|
|
|
+ $(_input).val('').focus();
|
|
|
StatTree.setSelectedNodeColumns(columns);
|
|
|
- $(_input).val('');
|
|
|
- StatTree.save();
|
|
|
+ StatTree.onSelected();
|
|
|
+ StatTree.setDirty();
|
|
|
return false;
|
|
|
});
|
|
|
|
|
@@ -626,7 +673,8 @@
|
|
|
columns[index] = x;
|
|
|
}
|
|
|
StatTree.setSelectedNodeColumns(columns);
|
|
|
- StatTree.save();
|
|
|
+ StatTree.onSelected();
|
|
|
+ StatTree.setDirty();
|
|
|
return false;
|
|
|
});
|
|
|
|
|
@@ -641,7 +689,8 @@
|
|
|
columns[index] = x;
|
|
|
}
|
|
|
StatTree.setSelectedNodeColumns(columns);
|
|
|
- StatTree.save();
|
|
|
+ StatTree.onSelected();
|
|
|
+ StatTree.setDirty();
|
|
|
return false;
|
|
|
});
|
|
|
|
|
@@ -651,7 +700,8 @@
|
|
|
let columns = StatTree.getSelectedNodeColumns();
|
|
|
columns.splice(+($(this).attr('data-index')), 1);
|
|
|
StatTree.setSelectedNodeColumns(columns);
|
|
|
- StatTree.save();
|
|
|
+ StatTree.onSelected();
|
|
|
+ StatTree.setDirty();
|
|
|
return false;
|
|
|
});
|
|
|
|
|
@@ -681,6 +731,20 @@
|
|
|
return false;
|
|
|
});
|
|
|
|
|
|
+ $(document)
|
|
|
+ .off('click', '#btn-save-tree')
|
|
|
+ .on('click', '#btn-save-tree', function() {
|
|
|
+ StatTree.save();
|
|
|
+ return false;
|
|
|
+ });
|
|
|
+
|
|
|
+ $(document)
|
|
|
+ .off('click', '.log-tree')
|
|
|
+ .on('click', '.log-tree', function() {
|
|
|
+ StatTree.log();
|
|
|
+ return false;
|
|
|
+ });
|
|
|
+
|
|
|
$(document)
|
|
|
.off('input change paste', '.frm-clause-add-edit input[name="question"], .frm-clause-add-edit input[name="answer"]')
|
|
|
.on('input change paste', '.frm-clause-add-edit input[name="question"], .frm-clause-add-edit input[name="answer"]', function() {
|
|
@@ -693,6 +757,11 @@
|
|
|
$('#refresh-counts')
|
|
|
.off('click')
|
|
|
.on('click', function() {
|
|
|
+ if(StatTree.changed) {
|
|
|
+ if(!window.confirm('Tree has not been saved. Changes will be lost if you continue. Continue?')) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ }
|
|
|
showMask();
|
|
|
$.post("{{ route('practice-management.api.statTree.refreshTreeCountQueries') }}", {
|
|
|
statTreeID: "{{ $statTree->id }}"
|
|
@@ -712,10 +781,6 @@
|
|
|
ClausesTree.load();
|
|
|
});
|
|
|
|
|
|
- addMCHook('reloadStatTree', function() {
|
|
|
- StatTree.load();
|
|
|
- });
|
|
|
-
|
|
|
}
|
|
|
addMCInitializer('stat-tree-edit-page', init, '#statTreeEdit');
|
|
|
}).call(window);
|