Commit | Line | Data |
---|---|---|
e7515b5b CW |
1 | (function(angular, $, _) { |
2 | "use strict"; | |
3 | ||
493f83d4 | 4 | angular.module('crmSearchAdmin').component('crmSearchAdminDisplay', { |
e7515b5b CW |
5 | bindings: { |
6 | savedSearch: '<', | |
7 | display: '<' | |
8 | }, | |
9e827e8e CW |
9 | require: { |
10 | crmSearchAdmin: '^crmSearchAdmin' | |
11 | }, | |
e7515b5b CW |
12 | template: function() { |
13 | // Dynamic template generates switch condition for each display type | |
14 | var html = | |
493f83d4 | 15 | '<div ng-include="\'~/crmSearchAdmin/crmSearchAdminDisplay.html\'"></div>\n' + |
e7515b5b | 16 | '<div ng-switch="$ctrl.display.type">\n'; |
493f83d4 | 17 | _.each(CRM.crmSearchAdmin.displayTypes, function(type) { |
e7515b5b | 18 | html += |
ecb9d1eb CW |
19 | '<div ng-switch-when="' + type.id + '">\n' + |
20 | ' <search-admin-display-' + type.id + ' api-entity="$ctrl.savedSearch.api_entity" api-params="$ctrl.savedSearch.api_params" display="$ctrl.display"></search-admin-display-' + type.id + '>\n' + | |
e7515b5b CW |
21 | ' <hr>\n' + |
22 | ' <button type="button" class="btn btn-{{ !$ctrl.stale ? \'success\' : $ctrl.preview ? \'warning\' : \'primary\' }}" ng-click="$ctrl.previewDisplay()" ng-disabled="!$ctrl.stale">\n' + | |
23 | ' <i class="crm-i ' + type.icon + '"></i>' + | |
24 | ' {{ $ctrl.preview && $ctrl.stale ? ts("Refresh") : ts("Preview") }}\n' + | |
25 | ' </button>\n' + | |
26 | ' <hr>\n' + | |
27 | ' <div ng-if="$ctrl.preview">\n' + | |
406f1014 | 28 | ' <' + type.name + ' api-entity="{{:: $ctrl.savedSearch.api_entity }}" search="$ctrl.savedSearch" display="$ctrl.display" settings="$ctrl.display.settings"></' + type.name + '>\n' + |
e7515b5b CW |
29 | ' </div>\n' + |
30 | '</div>\n'; | |
31 | }); | |
32 | html += '</div>'; | |
33 | return html; | |
34 | }, | |
03b55607 | 35 | controller: function($scope, $timeout, searchMeta) { |
33e81cf6 | 36 | var ts = $scope.ts = CRM.ts('org.civicrm.search_kit'), |
02c7fc51 CW |
37 | ctrl = this, |
38 | afforms; | |
e7515b5b | 39 | |
5623bf2a CW |
40 | this.isSuperAdmin = CRM.checkPerm('all CiviCRM permissions and ACLs'); |
41 | this.aclBypassHelp = ts('Only users with "all CiviCRM permissions and ACLs" can disable permission checks.'); | |
42 | ||
9e827e8e CW |
43 | this.preview = this.stale = false; |
44 | ||
daa4e55a CW |
45 | this.colTypes = { |
46 | links: { | |
47 | label: ts('Links'), | |
48 | icon: 'fa-link', | |
49 | defaults: { | |
50 | links: [] | |
51 | } | |
52 | }, | |
53 | buttons: { | |
54 | label: ts('Buttons'), | |
55 | icon: 'fa-square-o', | |
56 | defaults: { | |
57 | size: 'btn-sm', | |
58 | links: [] | |
59 | } | |
60 | }, | |
61 | menu: { | |
62 | label: ts('Menu'), | |
63 | icon: 'fa-bars', | |
64 | defaults: { | |
65 | text: ts('Actions'), | |
66 | style: 'default', | |
67 | size: 'btn-sm', | |
68 | icon: 'fa-bars', | |
69 | links: [] | |
70 | } | |
71 | }, | |
2ee83785 CW |
72 | include: { |
73 | label: ts('Custom Code'), | |
74 | icon: 'fa-code', | |
75 | defaults: { | |
76 | path: '' | |
77 | } | |
78 | } | |
daa4e55a CW |
79 | }; |
80 | ||
0458a613 | 81 | // Drag-n-drop settings for reordering columns |
969245e4 CW |
82 | this.sortableOptions = { |
83 | connectWith: '.crm-search-admin-edit-columns', | |
0458a613 CW |
84 | containment: '.crm-search-admin-edit-columns-wrapper', |
85 | cancel: 'input,textarea,button,select,option,a,label' | |
969245e4 CW |
86 | }; |
87 | ||
daa4e55a CW |
88 | this.styles = CRM.crmSearchAdmin.styles; |
89 | ||
90 | this.addCol = function(type) { | |
91 | var col = _.cloneDeep(this.colTypes[type].defaults); | |
92 | col.type = type; | |
93 | if (this.display.type === 'table') { | |
94 | col.alignment = 'text-right'; | |
95 | } | |
96 | ctrl.display.settings.columns.push(col); | |
97 | }; | |
98 | ||
969245e4 | 99 | this.removeCol = function(index) { |
daa4e55a CW |
100 | if (ctrl.display.settings.columns[index].type === 'field') { |
101 | ctrl.hiddenColumns.push(ctrl.display.settings.columns[index]); | |
102 | } | |
969245e4 CW |
103 | ctrl.display.settings.columns.splice(index, 1); |
104 | }; | |
105 | ||
106 | this.restoreCol = function(index) { | |
107 | ctrl.display.settings.columns.push(ctrl.hiddenColumns[index]); | |
108 | ctrl.hiddenColumns.splice(index, 1); | |
109 | }; | |
110 | ||
a3caaf9e CW |
111 | this.getExprFromSelect = function(key) { |
112 | var match; | |
113 | _.each(ctrl.savedSearch.api_params.select, function(expr) { | |
114 | var parts = expr.split(' AS '); | |
115 | if (_.includes(parts, key)) { | |
116 | match = parts[0]; | |
117 | return false; | |
118 | } | |
119 | }); | |
120 | return match; | |
121 | }; | |
122 | ||
123 | this.getFieldLabel = function(key) { | |
124 | var expr = ctrl.getExprFromSelect(key); | |
125 | return searchMeta.getDefaultLabel(expr); | |
126 | }; | |
127 | ||
daa4e55a CW |
128 | this.getColLabel = function(col) { |
129 | if (col.type === 'field') { | |
130 | return ctrl.getFieldLabel(col.key); | |
131 | } | |
132 | return ctrl.colTypes[col.type].label; | |
133 | }; | |
134 | ||
b2ee26f0 CW |
135 | this.toggleRewrite = function(col) { |
136 | if (col.rewrite) { | |
137 | col.rewrite = ''; | |
138 | } else { | |
139 | col.rewrite = '[' + col.key + ']'; | |
140 | delete col.editable; | |
141 | } | |
142 | }; | |
143 | ||
a58b7052 KJ |
144 | this.toggleImage = function(col) { |
145 | if (col.image) { | |
146 | delete col.image; | |
147 | } else { | |
148 | col.image = { | |
149 | alt: this.getColLabel(col) | |
150 | }; | |
151 | delete col.editable; | |
152 | } | |
153 | }; | |
154 | ||
b2ee26f0 CW |
155 | this.toggleEditable = function(col) { |
156 | if (col.editable) { | |
157 | delete col.editable; | |
c0fcc640 CW |
158 | } else { |
159 | col.editable = true; | |
b2ee26f0 | 160 | } |
b2ee26f0 CW |
161 | }; |
162 | ||
c0fcc640 | 163 | this.canBeEditable = function(col) { |
b2ee26f0 CW |
164 | var expr = ctrl.getExprFromSelect(col.key), |
165 | info = searchMeta.parseExpr(expr); | |
7891ca94 | 166 | return !col.image && !col.rewrite && !col.link && !info.fn && info.args[0] && info.args[0].field && !info.args[0].field.readonly; |
b2ee26f0 CW |
167 | }; |
168 | ||
f808224c CW |
169 | // Checks if a column contains a sortable value |
170 | // Must be a real sql expression (not a pseudo-field like `result_row_num`) | |
850492de CW |
171 | this.canBeSortable = function(col) { |
172 | var expr = ctrl.getExprFromSelect(col.key), | |
173 | info = searchMeta.parseExpr(expr), | |
f808224c | 174 | arg = (info && info.args && _.findWhere(info.args, {type: 'field'})) || {}; |
850492de CW |
175 | return arg.field && arg.field.type !== 'Pseudo'; |
176 | }; | |
177 | ||
2fe33e6c CW |
178 | // Aggregate functions (COUNT, AVG, MAX) cannot display as links, except for GROUP_CONCAT |
179 | // which gets special treatment in APIv4 to convert it to an array. | |
180 | this.canBeLink = function(col) { | |
181 | var expr = ctrl.getExprFromSelect(col.key), | |
182 | info = searchMeta.parseExpr(expr); | |
183 | return !info.fn || info.fn.category !== 'aggregate' || info.fn.name === 'GROUP_CONCAT'; | |
184 | }; | |
185 | ||
9446fbaa CW |
186 | var linkProps = ['path', 'entity', 'action', 'join', 'target']; |
187 | ||
2dbf2d72 CW |
188 | this.toggleLink = function(column) { |
189 | if (column.link) { | |
9446fbaa | 190 | ctrl.onChangeLink(column, {}); |
2dbf2d72 | 191 | } else { |
c0fcc640 | 192 | delete column.editable; |
d6704532 | 193 | var defaultLink = ctrl.getLinks(column.key)[0]; |
9446fbaa | 194 | ctrl.onChangeLink(column, defaultLink || {path: 'civicrm/'}); |
2dbf2d72 CW |
195 | } |
196 | }; | |
197 | ||
9446fbaa CW |
198 | this.onChangeLink = function(column, afterLink) { |
199 | column.link = column.link || {}; | |
200 | var beforeLink = column.link.action && _.findWhere(ctrl.getLinks(column.key), {action: column.link.action}); | |
201 | if (!afterLink.action && !afterLink.path) { | |
202 | if (beforeLink && beforeLink.text === column.title) { | |
2dbf2d72 CW |
203 | delete column.title; |
204 | } | |
205 | delete column.link; | |
9446fbaa CW |
206 | return; |
207 | } | |
208 | if (afterLink.text && ((!column.title && !beforeLink) || (beforeLink && beforeLink.text === column.title))) { | |
209 | column.title = afterLink.text; | |
210 | } else if (!afterLink.text && (beforeLink && beforeLink.text === column.title)) { | |
2dbf2d72 CW |
211 | delete column.title; |
212 | } | |
9446fbaa CW |
213 | _.each(linkProps, function(prop) { |
214 | column.link[prop] = afterLink[prop] || ''; | |
215 | }); | |
2dbf2d72 CW |
216 | }; |
217 | ||
d6704532 | 218 | this.getLinks = function(columnKey) { |
daa4e55a | 219 | if (!ctrl.links) { |
957358aa | 220 | ctrl.links = {'*': ctrl.crmSearchAdmin.buildLinks()}; |
daa4e55a | 221 | } |
d6704532 CW |
222 | if (!columnKey) { |
223 | return ctrl.links['*']; | |
224 | } | |
225 | var expr = ctrl.getExprFromSelect(columnKey), | |
226 | info = searchMeta.parseExpr(expr), | |
957358aa | 227 | joinEntity = searchMeta.getJoinEntity(info); |
d6704532 | 228 | if (!ctrl.links[joinEntity]) { |
957358aa | 229 | ctrl.links[joinEntity] = _.filter(ctrl.links['*'], {join: joinEntity}); |
d6704532 CW |
230 | } |
231 | return ctrl.links[joinEntity]; | |
daa4e55a CW |
232 | }; |
233 | ||
daa4e55a CW |
234 | this.pickIcon = function(model, key) { |
235 | searchMeta.pickIcon().then(function(icon) { | |
236 | model[key] = icon; | |
237 | }); | |
238 | }; | |
239 | ||
03b55607 | 240 | // Helper function to sort active from hidden columns and initialize each column with defaults |
69f0bd2b | 241 | this.initColumns = function(defaults) { |
03b55607 CW |
242 | if (!ctrl.display.settings.columns) { |
243 | ctrl.display.settings.columns = _.transform(ctrl.savedSearch.api_params.select, function(columns, fieldExpr) { | |
28218ad6 | 244 | columns.push(searchMeta.fieldToColumn(fieldExpr, defaults)); |
03b55607 | 245 | }); |
969245e4 | 246 | ctrl.hiddenColumns = []; |
03b55607 | 247 | } else { |
a3caaf9e CW |
248 | var activeColumns = _.collect(ctrl.display.settings.columns, 'key'), |
249 | selectAliases = _.map(ctrl.savedSearch.api_params.select, function(select) { | |
250 | return _.last(select.split(' AS ')); | |
251 | }); | |
969245e4 | 252 | ctrl.hiddenColumns = _.transform(ctrl.savedSearch.api_params.select, function(hiddenColumns, fieldExpr) { |
a3caaf9e CW |
253 | var key = _.last(fieldExpr.split(' AS ')); |
254 | if (!_.includes(activeColumns, key)) { | |
28218ad6 | 255 | hiddenColumns.push(searchMeta.fieldToColumn(fieldExpr, defaults)); |
03b55607 CW |
256 | } |
257 | }); | |
a3caaf9e | 258 | _.eachRight(activeColumns, function(key, index) { |
daa4e55a | 259 | if (key && !_.includes(selectAliases, key)) { |
03b55607 CW |
260 | ctrl.display.settings.columns.splice(index, 1); |
261 | } | |
262 | }); | |
03b55607 CW |
263 | } |
264 | }; | |
265 | ||
e7515b5b CW |
266 | this.previewDisplay = function() { |
267 | ctrl.preview = !ctrl.preview; | |
268 | ctrl.stale = false; | |
269 | if (!ctrl.preview) { | |
270 | $timeout(function() { | |
271 | ctrl.preview = true; | |
272 | }, 100); | |
273 | } | |
274 | }; | |
275 | ||
9e827e8e CW |
276 | this.fieldsForSort = function() { |
277 | function disabledIf(key) { | |
278 | return _.findIndex(ctrl.display.settings.sort, [key]) >= 0; | |
279 | } | |
280 | return { | |
9a0f174b CW |
281 | results: [ |
282 | { | |
283 | text: ts('Random'), | |
284 | icon: 'crm-i fa-random', | |
285 | id: 'RAND()', | |
286 | disabled: disabledIf('RAND()') | |
287 | }, | |
288 | { | |
289 | text: ts('Columns'), | |
290 | children: ctrl.crmSearchAdmin.getSelectFields(disabledIf) | |
291 | } | |
292 | ].concat(ctrl.crmSearchAdmin.getAllFields('', ['Field', 'Custom'], disabledIf)) | |
9e827e8e CW |
293 | }; |
294 | }; | |
295 | ||
296 | // Generic function to add to a setting array if the item is not already there | |
297 | this.pushSetting = function(name, value) { | |
298 | ctrl.display.settings[name] = ctrl.display.settings[name] || []; | |
299 | if (_.findIndex(ctrl.display.settings[name], value) < 0) { | |
300 | ctrl.display.settings[name].push(value); | |
301 | } | |
302 | }; | |
303 | ||
e7515b5b CW |
304 | $scope.$watch('$ctrl.display.settings', function() { |
305 | ctrl.stale = true; | |
306 | }, true); | |
307 | } | |
308 | }); | |
309 | ||
310 | })(angular, CRM.$, CRM._); |