1 (function(angular
, $, _
) {
4 // Trait provides base methods and properties common to all search display types
5 angular
.module('crmSearchDisplay').factory('searchDisplayBaseTrait', function(crmApi4
) {
6 var ts
= CRM
.ts('org.civicrm.search_kit');
8 // Replace tokens keyed to rowData.
9 // If rowMeta is provided, values will be formatted; if omitted, raw values will be provided.
10 function replaceTokens(str
, rowData
, rowMeta
, index
) {
14 _
.each(rowData
, function(value
, key
) {
15 if (str
.indexOf('[' + key
+ ']') >= 0) {
16 var column
= rowMeta
&& _
.findWhere(rowMeta
, {key
: key
}),
17 val
= column
? formatRawValue(column
, value
) : value
,
18 replacement
= angular
.isArray(val
) ? val
[index
|| 0] : val
;
19 str
= str
.replace(new RegExp(_
.escapeRegExp('[' + key
+ ']', 'g')), replacement
);
25 function getUrl(link
, rowData
, index
) {
26 var url
= replaceTokens(link
, rowData
, null, index
);
27 if (url
.slice(0, 1) !== '/' && url
.slice(0, 4) !== 'http') {
33 // Returns display value for a single column in a row
34 function formatDisplayValue(rowData
, key
, columns
) {
35 var column
= _
.findWhere(columns
, {key
: key
}),
36 displayValue
= column
.rewrite
? replaceTokens(column
.rewrite
, rowData
, columns
) : formatRawValue(column
, rowData
[key
]);
37 return angular
.isArray(displayValue
) ? displayValue
.join(', ') : displayValue
;
40 // Returns value and url for a column formatted as link(s)
41 function formatLinks(rowData
, key
, columns
) {
42 var column
= _
.findWhere(columns
, {key
: key
}),
43 value
= formatRawValue(column
, rowData
[key
]),
44 values
= angular
.isArray(value
) ? value
: [value
],
46 _
.each(values
, function(value
, index
) {
49 url
: getUrl(column
.link
.path
, rowData
, index
)
55 // Formats raw field value according to data type
56 function formatRawValue(column
, value
) {
57 var type
= column
&& column
.dataType
,
59 if (_
.isArray(value
)) {
60 return _
.map(value
, function(val
) {
61 return formatRawValue(column
, val
);
64 if (value
&& (type
=== 'Date' || type
=== 'Timestamp') && /^\d{4}-\d{2}-\d{2}/.test(value
)) {
65 result
= CRM
.utils
.formatDate(value
, null, type
=== 'Timestamp');
67 else if (type
=== 'Boolean' && typeof value
=== 'boolean') {
68 result
= value
? ts('Yes') : ts('No');
70 else if (type
=== 'Money' && typeof value
=== 'number') {
71 result
= CRM
.formatMoney(value
);
76 // Return a base trait shared by all search display controllers
77 // Gets mixed in using angular.extend()
83 // Called by the controller's $onInit function
84 initializeDisplay: function($scope
, $element
) {
86 this.limit
= this.settings
.limit
;
87 this.sort
= this.settings
.sort
? _
.cloneDeep(this.settings
.sort
) : [];
89 this.getResults
= _
.debounce(function() {
93 // If search is embedded in contact summary tab, display count in tab-header
94 var contactTab
= $element
.closest('.crm-contact-page .ui-tabs-panel').attr('id');
96 var unwatchCount
= $scope
.$watch('$ctrl.rowCount', function(rowCount
) {
97 if (typeof rowCount
=== 'number') {
99 CRM
.tabHeader
.updateCount(contactTab
.replace('contact-', '#tab_'), rowCount
);
104 function onChangeFilters() {
106 ctrl
.rowCount
= null;
107 if (ctrl
.onChangeFilters
) {
108 ctrl
.onChangeFilters();
113 function onChangePageSize() {
118 if (this.afFieldset
) {
119 $scope
.$watch(this.afFieldset
.getFieldData
, onChangeFilters
, true);
121 if (this.settings
.pager
&& this.settings
.pager
.expose_limit
) {
122 $scope
.$watch('$ctrl.limit', onChangePageSize
);
124 $scope
.$watch('$ctrl.filters', onChangeFilters
, true);
127 // Generate params for the SearchDisplay.run api
128 getApiParams: function(mode
) {
130 return: mode
|| 'page:' + this.page
,
131 savedSearch
: this.search
,
132 display
: this.display
,
135 filters
: _
.assign({}, (this.afFieldset
? this.afFieldset
.getFieldData() : {}), this.filters
),
136 afform
: this.afFieldset
? this.afFieldset
.getFormName() : null
140 // Call SearchDisplay.run and update ctrl.results and ctrl.rowCount
141 runSearch: function() {
143 return crmApi4('SearchDisplay', 'run', ctrl
.getApiParams()).then(function(results
) {
144 ctrl
.results
= results
;
145 ctrl
.editing
= false;
146 if (!ctrl
.rowCount
) {
147 if (!ctrl
.limit
|| results
.length
< ctrl
.limit
) {
148 ctrl
.rowCount
= results
.length
;
149 } else if (ctrl
.settings
.pager
) {
150 var params
= ctrl
.getApiParams('row_count');
151 crmApi4('SearchDisplay', 'run', params
).then(function(result
) {
152 ctrl
.rowCount
= result
.count
;
158 replaceTokens: function(value
, row
) {
159 return replaceTokens(value
, row
, this.settings
.columns
);
161 getLinks: function(rowData
, col
) {
162 rowData
._links
= rowData
._links
|| {};
163 if (!(col
.key
in rowData
._links
)) {
164 rowData
._links
[col
.key
] = formatLinks(rowData
, col
.key
, this.settings
.columns
);
166 return rowData
._links
[col
.key
];
168 formatFieldValue: function(rowData
, col
) {
169 return formatDisplayValue(rowData
, col
.key
, this.settings
.columns
);
174 })(angular
, CRM
.$, CRM
._
);