1 // https://civicrm.org/licensing
2 (function(angular
, $, _
) {
5 angular
.module('afGuiEditor').component('afGuiSearch', {
6 templateUrl
: '~/afGuiEditor/afGuiSearch.html',
10 require
: {editor
: '^^afGuiEditor'},
11 controller: function ($scope
, $timeout
, afGui
) {
12 var ts
= $scope
.ts
= CRM
.ts('org.civicrm.afform_admin');
15 $scope
.fieldList
= [];
16 $scope
.calcFieldList
= [];
17 $scope
.blockList
= [];
18 $scope
.blockTitles
= [];
19 $scope
.elementList
= [];
20 $scope
.elementTitles
= [];
22 $scope
.getField
= afGui
.getField
;
24 this.buildPaletteLists = function() {
25 var search
= $scope
.controls
.fieldSearch
? $scope
.controls
.fieldSearch
.toLowerCase() : null;
26 buildCalcFieldList(search
);
27 buildFieldList(search
);
28 buildBlockList(search
);
29 buildElementList(search
);
32 function buildCalcFieldList(search
) {
33 $scope
.calcFieldList
.length
= 0;
34 _
.each(_
.cloneDeep(ctrl
.display
.calc_fields
), function(field
) {
35 if (!search
|| _
.contains(field
.defn
.label
.toLowerCase(), search
)) {
36 $scope
.calcFieldList
.push(field
);
41 function buildBlockList(search
) {
42 $scope
.blockList
.length
= 0;
43 $scope
.blockTitles
.length
= 0;
44 _
.each(afGui
.meta
.blocks
, function(block
, directive
) {
45 if (!search
|| _
.contains(directive
, search
) || _
.contains(block
.name
.toLowerCase(), search
) || _
.contains(block
.title
.toLowerCase(), search
)) {
46 var item
= {"#tag": directive
};
47 $scope
.blockList
.push(item
);
48 $scope
.blockTitles
.push(block
.title
);
53 function buildFieldList(search
) {
54 $scope
.fieldList
.length
= 0;
55 var entity
= afGui
.getEntity(ctrl
.display
['saved_search_id.api_entity']),
57 entityCount
[entity
.entity
] = 1;
58 $scope
.fieldList
.push({
59 entityType
: entity
.entity
,
60 label
: ts('%1 Fields', {1: entity
.label
}),
61 fields
: filterFields(entity
.fields
)
64 _
.each(ctrl
.display
['saved_search_id.api_params'].join
, function(join
) {
65 var joinInfo
= join
[0].split(' AS '),
66 entity
= afGui
.getEntity(joinInfo
[0]),
68 entityCount
[entity
.entity
] = (entityCount
[entity
.entity
] || 0) + 1;
69 $scope
.fieldList
.push({
70 entityType
: entity
.entity
,
71 label
: ts('%1 Fields', {1: entity
.label
+ (entityCount
[entity
.entity
] > 1 ? ' ' + entityCount
[entity
.entity
] : '')}),
72 fields
: filterFields(entity
.fields
, alias
)
76 function filterFields(fields
, prefix
) {
77 return _
.transform(fields
, function(fieldList
, field
) {
78 if (!search
|| _
.contains(field
.name
, search
) || _
.contains(field
.label
.toLowerCase(), search
)) {
79 fieldList
.push(fieldDefaults(field
, prefix
));
84 function fieldDefaults(field
, prefix
) {
87 name
: (prefix
? prefix
+ '.' : '') + field
.name
89 if (field
.input_type
=== 'Select' || field
.input_type
=== 'ChainSelect') {
90 tag
.defn
= {input_attrs
: {multiple
: true}};
91 } else if (field
.input_type
=== 'Date') {
92 tag
.defn
= {input_type
: 'Select', search_range
: true};
93 } else if (field
.options
) {
94 tag
.defn
= {input_type
: 'Select', input_attrs
: {multiple
: true}};
100 function buildElementList(search
) {
101 $scope
.elementList
.length
= 0;
102 $scope
.elementTitles
.length
= 0;
103 _
.each(afGui
.meta
.elements
, function(element
, name
) {
104 if (!search
|| _
.contains(name
, search
) || _
.contains(element
.title
.toLowerCase(), search
)) {
105 var node
= _
.cloneDeep(element
.element
);
106 if (name
=== 'fieldset') {
109 $scope
.elementList
.push(node
);
110 $scope
.elementTitles
.push(element
.title
);
115 // This gets called from jquery-ui so we have to manually apply changes to scope
116 $scope
.buildPaletteLists = function() {
117 $timeout(function() {
118 $scope
.$apply(function() {
119 ctrl
.buildPaletteLists();
124 // Checks if a field is on the form or set as a value
125 $scope
.fieldInUse = function(fieldName
) {
126 return check(ctrl
.editor
.layout
['#children'], {'#tag': 'af-field', name
: fieldName
});
129 // Checks if fields in a block are already in use on the form.
130 // Note that if a block contains no fields it can be used repeatedly, so this will always return false for those.
131 $scope
.blockInUse = function(block
) {
132 if (block
['af-join']) {
133 return check(ctrl
.editor
.layout
['#children'], {'af-join': block
['af-join']});
135 var fieldsInBlock
= _
.pluck(afGui
.findRecursive(afGui
.meta
.blocks
[block
['#tag']].layout
, {'#tag': 'af-field'}), 'name');
136 return check(ctrl
.editor
.layout
['#children'], function(item
) {
137 return item
['#tag'] === 'af-field' && _
.includes(fieldsInBlock
, item
.name
);
141 // Check for a matching item for this entity
142 // Recursively checks the form layout, including block directives
143 function check(group
, criteria
, found
) {
147 if (_
.find(group
, criteria
)) {
151 _
.each(group
, function(item
) {
155 if (_
.isPlainObject(item
)) {
156 // Recurse through everything
157 if (item
['#children']) {
158 check(item
['#children'], criteria
, found
);
160 // Recurse into block directives
161 else if (item
['#tag'] && item
['#tag'] in afGui
.meta
.blocks
) {
162 check(afGui
.meta
.blocks
[item
['#tag']].layout
, criteria
, found
);
169 this.$onInit = function() {
170 // When a new block is saved, update the list
171 this.meta
= afGui
.meta
;
172 $scope
.$watchCollection('$ctrl.meta.blocks', function() {
173 $scope
.controls
.fieldSearch
= '';
174 ctrl
.buildPaletteLists();
180 })(angular
, CRM
.$, CRM
._
);