Commit | Line | Data |
---|---|---|
ab4e6f8a CW |
1 | (function(angular, $, _) { |
2 | "use strict"; | |
3 | ||
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'); | |
7 | ||
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) { | |
11 | if (!str) { | |
12 | return ''; | |
13 | } | |
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); | |
20 | } | |
21 | }); | |
22 | return str; | |
23 | } | |
24 | ||
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') { | |
28 | url = CRM.url(url); | |
29 | } | |
30 | return url; | |
31 | } | |
32 | ||
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; | |
38 | } | |
39 | ||
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], | |
45 | links = []; | |
46 | _.each(values, function(value, index) { | |
47 | links.push({ | |
48 | value: value, | |
49 | url: getUrl(column.link.path, rowData, index) | |
50 | }); | |
51 | }); | |
52 | return links; | |
53 | } | |
54 | ||
55 | // Formats raw field value according to data type | |
56 | function formatRawValue(column, value) { | |
57 | var type = column && column.dataType, | |
58 | result = value; | |
59 | if (_.isArray(value)) { | |
60 | return _.map(value, function(val) { | |
61 | return formatRawValue(column, val); | |
62 | }); | |
63 | } | |
64 | if (value && (type === 'Date' || type === 'Timestamp') && /^\d{4}-\d{2}-\d{2}/.test(value)) { | |
65 | result = CRM.utils.formatDate(value, null, type === 'Timestamp'); | |
66 | } | |
67 | else if (type === 'Boolean' && typeof value === 'boolean') { | |
68 | result = value ? ts('Yes') : ts('No'); | |
69 | } | |
70 | else if (type === 'Money' && typeof value === 'number') { | |
71 | result = CRM.formatMoney(value); | |
72 | } | |
73 | return result; | |
74 | } | |
75 | ||
76 | // Return a base trait shared by all search display controllers | |
77 | // Gets mixed in using angular.extend() | |
78 | return { | |
79 | page: 1, | |
80 | rowCount: null, | |
81 | getUrl: getUrl, | |
82 | ||
83 | // Called by the controller's $onInit function | |
84 | initializeDisplay: function($scope, $element) { | |
85 | var ctrl = this; | |
10cd9d37 | 86 | this.limit = this.settings.limit; |
ab4e6f8a CW |
87 | this.sort = this.settings.sort ? _.cloneDeep(this.settings.sort) : []; |
88 | ||
b7fd7a81 CW |
89 | this.getResults = _.debounce(function() { |
90 | ctrl.runSearch(); | |
ab4e6f8a CW |
91 | }, 100); |
92 | ||
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'); | |
95 | if (contactTab) { | |
96 | var unwatchCount = $scope.$watch('$ctrl.rowCount', function(rowCount) { | |
97 | if (typeof rowCount === 'number') { | |
98 | unwatchCount(); | |
99 | CRM.tabHeader.updateCount(contactTab.replace('contact-', '#tab_'), rowCount); | |
100 | } | |
101 | }); | |
102 | } | |
103 | ||
104 | function onChangeFilters() { | |
105 | ctrl.page = 1; | |
106 | ctrl.rowCount = null; | |
107 | if (ctrl.onChangeFilters) { | |
108 | ctrl.onChangeFilters(); | |
109 | } | |
b7fd7a81 | 110 | ctrl.getResults(); |
ab4e6f8a CW |
111 | } |
112 | ||
10cd9d37 CW |
113 | function onChangePageSize() { |
114 | ctrl.page = 1; | |
115 | ctrl.getResults(); | |
116 | } | |
117 | ||
ab4e6f8a CW |
118 | if (this.afFieldset) { |
119 | $scope.$watch(this.afFieldset.getFieldData, onChangeFilters, true); | |
120 | } | |
10cd9d37 CW |
121 | if (this.settings.pager && this.settings.pager.expose_limit) { |
122 | $scope.$watch('$ctrl.limit', onChangePageSize); | |
123 | } | |
ab4e6f8a CW |
124 | $scope.$watch('$ctrl.filters', onChangeFilters, true); |
125 | }, | |
126 | ||
127 | // Generate params for the SearchDisplay.run api | |
128 | getApiParams: function(mode) { | |
129 | return { | |
130 | return: mode || 'page:' + this.page, | |
131 | savedSearch: this.search, | |
132 | display: this.display, | |
133 | sort: this.sort, | |
10cd9d37 | 134 | limit: this.limit, |
ab4e6f8a CW |
135 | filters: _.assign({}, (this.afFieldset ? this.afFieldset.getFieldData() : {}), this.filters), |
136 | afform: this.afFieldset ? this.afFieldset.getFormName() : null | |
137 | }; | |
138 | }, | |
139 | ||
140 | // Call SearchDisplay.run and update ctrl.results and ctrl.rowCount | |
b7fd7a81 | 141 | runSearch: function() { |
ab4e6f8a CW |
142 | var ctrl = this; |
143 | return crmApi4('SearchDisplay', 'run', ctrl.getApiParams()).then(function(results) { | |
144 | ctrl.results = results; | |
145 | ctrl.editing = false; | |
146 | if (!ctrl.rowCount) { | |
10cd9d37 | 147 | if (!ctrl.limit || results.length < ctrl.limit) { |
ab4e6f8a CW |
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; | |
153 | }); | |
154 | } | |
155 | } | |
156 | }); | |
157 | }, | |
158 | replaceTokens: function(value, row) { | |
159 | return replaceTokens(value, row, this.settings.columns); | |
160 | }, | |
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); | |
165 | } | |
166 | return rowData._links[col.key]; | |
167 | }, | |
168 | formatFieldValue: function(rowData, col) { | |
169 | return formatDisplayValue(rowData, col.key, this.settings.columns); | |
170 | } | |
171 | }; | |
172 | }); | |
173 | ||
174 | })(angular, CRM.$, CRM._); |