Afform GUI - Rename service from afAdmin to afGiu
[civicrm-core.git] / ext / afform / admin / ang / afGuiEditor / afGuiEntity.component.js
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'},
11 controller: function ($scope, $timeout, afGui) {
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() {
26 return afGui.meta.entities[getEntityType()];
27 };
28
29 $scope.getField = afGui.getField;
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
58 _.each(afGui.meta.entities, function(entity, entityName) {
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;
84 _.each(afGui.meta.blocks, function(block, directive) {
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;
109 _.each(afGui.meta.elements, function(element, name) {
110 if (!search || _.contains(name, search) || _.contains(element.title.toLowerCase(), search)) {
111 var node = _.cloneDeep(element.element);
112 if (name === 'fieldset') {
113 node['af-fieldset'] = ctrl.entity.name;
114 }
115 $scope.elementList.push(node);
116 $scope.elementTitles.push(name === 'fieldset' ? ts('Fieldset for %1', {1: ctrl.entity.label}) : element.title);
117 }
118 });
119 }
120
121 $scope.clearSearch = function() {
122 $scope.controls.fieldSearch = '';
123 };
124
125 // This gets called from jquery-ui so we have to manually apply changes to scope
126 $scope.buildPaletteLists = function() {
127 $timeout(function() {
128 $scope.$apply(function() {
129 buildPaletteLists();
130 });
131 });
132 };
133
134 // Checks if a field is on the form or set as a value
135 $scope.fieldInUse = function(fieldName) {
136 var data = ctrl.entity.data || {};
137 if (fieldName in data) {
138 return true;
139 }
140 return check(ctrl.editor.layout['#children'], {'#tag': 'af-field', name: fieldName});
141 };
142
143 $scope.blockInUse = function(block) {
144 if (block['af-join']) {
145 return check(ctrl.editor.layout['#children'], {'af-join': block['af-join']});
146 }
147 var fieldsInBlock = _.pluck(afGui.findRecursive(afGui.meta.blocks[block['#tag']].layout, {'#tag': 'af-field'}), 'name');
148 return check(ctrl.editor.layout['#children'], function(item) {
149 return item['#tag'] === 'af-field' && _.includes(fieldsInBlock, item.name);
150 });
151 };
152
153 // Check for a matching item for this entity
154 // Recursively checks the form layout, including block directives
155 function check(group, criteria, found) {
156 if (!found) {
157 found = {};
158 }
159 if (_.find(group, criteria)) {
160 found.match = true;
161 return true;
162 }
163 _.each(group, function(item) {
164 if (found.match) {
165 return false;
166 }
167 if (_.isPlainObject(item)) {
168 // Recurse through everything but skip fieldsets for other entities
169 if ((!item['af-fieldset'] || (item['af-fieldset'] === ctrl.entity.name)) && item['#children']) {
170 check(item['#children'], criteria, found);
171 }
172 // Recurse into block directives
173 else if (item['#tag'] && item['#tag'] in afGui.meta.blocks) {
174 check(afGui.meta.blocks[item['#tag']].layout, criteria, found);
175 }
176 }
177 });
178 return found.match;
179 }
180
181 $scope.$watch('controls.addValue', function(fieldName) {
182 if (fieldName) {
183 if (!ctrl.entity.data) {
184 ctrl.entity.data = {};
185 }
186 ctrl.entity.data[fieldName] = '';
187 $scope.controls.addValue = '';
188 }
189 });
190
191 $scope.$watch('controls.fieldSearch', buildPaletteLists);
192 }
193 });
194
195 })(angular, CRM.$, CRM._);