Afform Gui - Support editing blocks
[civicrm-core.git] / ext / afform / admin / ang / afGuiEditor / afGuiEntity.component.js
CommitLineData
b844d2ca
CW
1// https://civicrm.org/licensing
2(function(angular, $, _) {
3 "use strict";
4
5 angular.module('afGuiEditor').component('afGuiEntity', {
6 templateUrl: '~/afGuiEditor/afGuiEntity.html',
7 bindings: {
8 entity: '<'
9 },
10 require: {editor: '^^afGuiEditor'},
23fd8685 11 controller: function ($scope, $timeout, afGui) {
b844d2ca
CW
12 var ts = $scope.ts = CRM.ts();
13 var ctrl = this;
14 $scope.controls = {};
15 $scope.fieldList = [];
16 $scope.blockList = [];
17 $scope.blockTitles = [];
18 $scope.elementList = [];
19 $scope.elementTitles = [];
20
21 function getEntityType() {
22 return ctrl.entity.type === 'Contact' ? ctrl.entity.data.contact_type : ctrl.entity.type;
23 }
24
25 $scope.getMeta = function() {
23fd8685 26 return afGui.meta.entities[getEntityType()];
b844d2ca
CW
27 };
28
23fd8685 29 $scope.getField = afGui.getField;
b844d2ca
CW
30
31 $scope.valuesFields = function() {
32 var fields = _.transform($scope.getMeta().fields, function(fields, field) {
33 fields.push({id: field.name, text: field.label, disabled: $scope.fieldInUse(field.name)});
34 }, []);
35 return {results: fields};
36 };
37
38 $scope.removeValue = function(entity, fieldName) {
39 delete entity.data[fieldName];
40 };
41
42 function buildPaletteLists() {
43 var search = $scope.controls.fieldSearch ? $scope.controls.fieldSearch.toLowerCase() : null;
44 buildFieldList(search);
45 buildBlockList(search);
46 buildElementList(search);
47 }
48
49 function buildFieldList(search) {
50 $scope.fieldList.length = 0;
51 $scope.fieldList.push({
52 entityName: ctrl.entity.name,
53 entityType: getEntityType(),
54 label: ts('%1 Fields', {1: $scope.getMeta().label}),
55 fields: filterFields($scope.getMeta().fields)
56 });
57
23fd8685 58 _.each(afGui.meta.entities, function(entity, entityName) {
b844d2ca
CW
59 if (check(ctrl.editor.layout['#children'], {'af-join': entityName})) {
60 $scope.fieldList.push({
61 entityName: ctrl.entity.name + '-join-' + entityName,
62 entityType: entityName,
63 label: ts('%1 Fields', {1: entity.label}),
64 fields: filterFields(entity.fields)
65 });
66 }
67 });
68
69 function filterFields(fields) {
70 return _.transform(fields, function(fieldList, field) {
71 if (!search || _.contains(field.name, search) || _.contains(field.label.toLowerCase(), search)) {
72 fieldList.push({
73 "#tag": "af-field",
74 name: field.name
75 });
76 }
77 }, []);
78 }
79 }
80
81 function buildBlockList(search) {
82 $scope.blockList.length = 0;
83 $scope.blockTitles.length = 0;
23fd8685 84 _.each(afGui.meta.blocks, function(block, directive) {
b844d2ca
CW
85 if ((!search || _.contains(directive, search) || _.contains(block.name.toLowerCase(), search) || _.contains(block.title.toLowerCase(), search)) &&
86 (block.block === '*' || block.block === ctrl.entity.type || (ctrl.entity.type === 'Contact' && block.block === ctrl.entity.data.contact_type))
87 ) {
88 var item = {"#tag": block.join ? "div" : directive};
89 if (block.join) {
90 item['af-join'] = block.join;
91 item['#children'] = [{"#tag": directive}];
92 }
93 if (block.repeat) {
94 item['af-repeat'] = ts('Add');
95 item.min = '1';
96 if (typeof block.repeat === 'number') {
97 item.max = '' + block.repeat;
98 }
99 }
100 $scope.blockList.push(item);
101 $scope.blockTitles.push(block.title);
102 }
103 });
104 }
105
106 function buildElementList(search) {
107 $scope.elementList.length = 0;
108 $scope.elementTitles.length = 0;
23fd8685 109 _.each(afGui.meta.elements, function(element, name) {
b844d2ca
CW
110 if (!search || _.contains(name, search) || _.contains(element.title.toLowerCase(), search)) {
111 var node = _.cloneDeep(element.element);
112 if (name === 'fieldset') {
fbcd8c17
CW
113 if (!ctrl.editor.allowEntityConfig) {
114 return;
115 }
b844d2ca
CW
116 node['af-fieldset'] = ctrl.entity.name;
117 }
118 $scope.elementList.push(node);
119 $scope.elementTitles.push(name === 'fieldset' ? ts('Fieldset for %1', {1: ctrl.entity.label}) : element.title);
120 }
121 });
122 }
123
124 $scope.clearSearch = function() {
125 $scope.controls.fieldSearch = '';
126 };
127
128 // This gets called from jquery-ui so we have to manually apply changes to scope
129 $scope.buildPaletteLists = function() {
130 $timeout(function() {
131 $scope.$apply(function() {
132 buildPaletteLists();
133 });
134 });
135 };
136
137 // Checks if a field is on the form or set as a value
138 $scope.fieldInUse = function(fieldName) {
139 var data = ctrl.entity.data || {};
140 if (fieldName in data) {
141 return true;
142 }
143 return check(ctrl.editor.layout['#children'], {'#tag': 'af-field', name: fieldName});
144 };
145
146 $scope.blockInUse = function(block) {
147 if (block['af-join']) {
148 return check(ctrl.editor.layout['#children'], {'af-join': block['af-join']});
149 }
23fd8685 150 var fieldsInBlock = _.pluck(afGui.findRecursive(afGui.meta.blocks[block['#tag']].layout, {'#tag': 'af-field'}), 'name');
b844d2ca
CW
151 return check(ctrl.editor.layout['#children'], function(item) {
152 return item['#tag'] === 'af-field' && _.includes(fieldsInBlock, item.name);
153 });
154 };
155
156 // Check for a matching item for this entity
157 // Recursively checks the form layout, including block directives
158 function check(group, criteria, found) {
159 if (!found) {
160 found = {};
161 }
162 if (_.find(group, criteria)) {
163 found.match = true;
164 return true;
165 }
166 _.each(group, function(item) {
167 if (found.match) {
168 return false;
169 }
170 if (_.isPlainObject(item)) {
171 // Recurse through everything but skip fieldsets for other entities
172 if ((!item['af-fieldset'] || (item['af-fieldset'] === ctrl.entity.name)) && item['#children']) {
173 check(item['#children'], criteria, found);
174 }
175 // Recurse into block directives
23fd8685
CW
176 else if (item['#tag'] && item['#tag'] in afGui.meta.blocks) {
177 check(afGui.meta.blocks[item['#tag']].layout, criteria, found);
b844d2ca
CW
178 }
179 }
180 });
181 return found.match;
182 }
183
184 $scope.$watch('controls.addValue', function(fieldName) {
185 if (fieldName) {
186 if (!ctrl.entity.data) {
187 ctrl.entity.data = {};
188 }
189 ctrl.entity.data[fieldName] = '';
190 $scope.controls.addValue = '';
191 }
192 });
193
194 $scope.$watch('controls.fieldSearch', buildPaletteLists);
195 }
196 });
197
198})(angular, CRM.$, CRM._);