// Declare module
angular.module('crmSearchDisplay', CRM.angRequires('crmSearchDisplay'))
- .factory('searchDisplayUtils', function(crmApi4) {
+ // Provides base methods and properties common to all search display types
+ .factory('searchDisplayBaseTrait', function(crmApi4) {
+ var ts = CRM.ts('org.civicrm.search_kit');
// Replace tokens keyed to rowData.
// If rowMeta is provided, values will be formatted; if omitted, raw values will be provided.
return result;
}
- function getApiParams(ctrl, mode) {
- return {
- return: mode || 'page:' + ctrl.page,
- savedSearch: ctrl.search,
- display: ctrl.display,
- sort: ctrl.sort,
- filters: _.assign({}, (ctrl.afFieldset ? ctrl.afFieldset.getFieldData() : {}), ctrl.filters),
- afform: ctrl.afFieldset ? ctrl.afFieldset.getFormName() : null
- };
- }
+ // Return a base trait shared by all search display controllers
+ // Gets mixed in using angular.extend()
+ return {
+ page: 1,
+ rowCount: null,
+ getUrl: getUrl,
+
+ // Called by the controller's $onInit function
+ initializeDisplay: function($scope, $element) {
+ var ctrl = this;
+ this.sort = this.settings.sort ? _.cloneDeep(this.settings.sort) : [];
+
+ $scope.getResults = _.debounce(function() {
+ ctrl.getResults();
+ }, 100);
- function getResults(ctrl) {
- return crmApi4('SearchDisplay', 'run', getApiParams(ctrl)).then(function(results) {
- ctrl.results = results;
- ctrl.editing = false;
- if (!ctrl.rowCount) {
- if (!ctrl.settings.limit || results.length < ctrl.settings.limit) {
- ctrl.rowCount = results.length;
- } else if (ctrl.settings.pager) {
- var params = getApiParams(ctrl, 'row_count');
- crmApi4('SearchDisplay', 'run', params).then(function(result) {
- ctrl.rowCount = result.count;
- });
+ // If search is embedded in contact summary tab, display count in tab-header
+ var contactTab = $element.closest('.crm-contact-page .ui-tabs-panel').attr('id');
+ if (contactTab) {
+ var unwatchCount = $scope.$watch('$ctrl.rowCount', function(rowCount) {
+ if (typeof rowCount === 'number') {
+ unwatchCount();
+ CRM.tabHeader.updateCount(contactTab.replace('contact-', '#tab_'), rowCount);
+ }
+ });
+ }
+
+ function onChangeFilters() {
+ ctrl.page = 1;
+ ctrl.rowCount = null;
+ if (ctrl.onChangeFilters) {
+ ctrl.onChangeFilters();
}
+ $scope.getResults();
}
- });
- }
- return {
- formatDisplayValue: formatDisplayValue,
- formatLinks: formatLinks,
- getApiParams: getApiParams,
- getResults: getResults,
- replaceTokens: replaceTokens,
- getUrl: getUrl
+ if (this.afFieldset) {
+ $scope.$watch(this.afFieldset.getFieldData, onChangeFilters, true);
+ }
+ $scope.$watch('$ctrl.filters', onChangeFilters, true);
+ },
+
+ // Generate params for the SearchDisplay.run api
+ getApiParams: function(mode) {
+ return {
+ return: mode || 'page:' + this.page,
+ savedSearch: this.search,
+ display: this.display,
+ sort: this.sort,
+ filters: _.assign({}, (this.afFieldset ? this.afFieldset.getFieldData() : {}), this.filters),
+ afform: this.afFieldset ? this.afFieldset.getFormName() : null
+ };
+ },
+
+ // Call SearchDisplay.run and update ctrl.results and ctrl.rowCount
+ getResults: function() {
+ var ctrl = this;
+ return crmApi4('SearchDisplay', 'run', ctrl.getApiParams()).then(function(results) {
+ ctrl.results = results;
+ ctrl.editing = false;
+ if (!ctrl.rowCount) {
+ if (!ctrl.settings.limit || results.length < ctrl.settings.limit) {
+ ctrl.rowCount = results.length;
+ } else if (ctrl.settings.pager) {
+ var params = ctrl.getApiParams('row_count');
+ crmApi4('SearchDisplay', 'run', params).then(function(result) {
+ ctrl.rowCount = result.count;
+ });
+ }
+ }
+ });
+ },
+ replaceTokens: function(value, row) {
+ return replaceTokens(value, row, this.settings.columns);
+ },
+ getLinks: function(rowData, col) {
+ rowData._links = rowData._links || {};
+ if (!(col.key in rowData._links)) {
+ rowData._links[col.key] = formatLinks(rowData, col.key, this.settings.columns);
+ }
+ return rowData._links[col.key];
+ },
+ formatFieldValue: function(rowData, col) {
+ return formatDisplayValue(rowData, col.key, this.settings.columns);
+ }
};
});
boundary-links="true"
total-items="$ctrl.rowCount"
ng-model="$ctrl.page"
- ng-change="$ctrl.getResults()"
+ ng-change="getResults()"
items-per-page="$ctrl.settings.limit"
max-size="6"
force-ellipses="true"
<span ng-repeat="item in col.links">
- <a class="btn {{:: col.size }} btn-{{:: item.style }}" target="{{:: item.target }}" href="{{:: displayUtils.getUrl(item.path, row) }}">
+ <a class="btn {{:: col.size }} btn-{{:: item.style }}" target="{{:: item.target }}" href="{{:: $ctrl.getUrl(item.path, row) }}">
<i ng-if=":: item.icon" class="crm-i {{:: item.icon }}"></i>
{{:: $ctrl.replaceTokens(item.text, row) }}
</a>
<span ng-repeat="item in col.links">
- <a class="text-{{:: item.style }}" target="{{:: item.target }}" href="{{:: displayUtils.getUrl(item.path, row) }}">
+ <a class="text-{{:: item.style }}" target="{{:: item.target }}" href="{{:: $ctrl.getUrl(item.path, row) }}">
<i ng-if=":: item.icon" class="crm-i {{:: item.icon }}"></i>
{{:: $ctrl.replaceTokens(item.text, row) }}
</a>
</button>
<ul class="dropdown-menu {{ col.alignment === 'text-right' ? 'dropdown-menu-right' : '' }}" ng-if=":: col.open">
<li ng-repeat="item in col.links" class="bg-{{:: item.style }}">
- <a href="{{:: displayUtils.getUrl(item.path, row) }}" target="{{:: item.target }}">
+ <a href="{{:: $ctrl.getUrl(item.path, row) }}" target="{{:: item.target }}">
<i ng-if=":: item.icon" class="crm-i {{:: item.icon }}"></i>
{{:: $ctrl.replaceTokens(item.text, row) }}
</a>
afFieldset: '?^^afFieldset'
},
templateUrl: '~/crmSearchDisplayList/crmSearchDisplayList.html',
- controller: function($scope, $element, crmApi4, searchDisplayUtils) {
+ controller: function($scope, $element, searchDisplayBaseTrait) {
var ts = $scope.ts = CRM.ts('org.civicrm.search_kit'),
- ctrl = this;
-
- this.page = 1;
- this.rowCount = null;
+ // Mix in properties of searchDisplayBaseTrait
+ ctrl = angular.extend(this, searchDisplayBaseTrait);
this.$onInit = function() {
- this.sort = this.settings.sort ? _.cloneDeep(this.settings.sort) : [];
- $scope.displayUtils = searchDisplayUtils;
-
- // If search is embedded in contact summary tab, display count in tab-header
- var contactTab = $element.closest('.crm-contact-page .ui-tabs-panel').attr('id');
- if (contactTab) {
- var unwatchCount = $scope.$watch('$ctrl.rowCount', function(rowCount) {
- if (typeof rowCount === 'number') {
- unwatchCount();
- CRM.tabHeader.updateCount(contactTab.replace('contact-', '#tab_'), rowCount);
- }
- });
- }
-
- if (this.afFieldset) {
- $scope.$watch(this.afFieldset.getFieldData, onChangeFilters, true);
- }
- $scope.$watch('$ctrl.filters', onChangeFilters, true);
+ this.initializeDisplay($scope, $element);
};
- this.getResults = _.debounce(function() {
- searchDisplayUtils.getResults(ctrl);
- }, 100);
-
// Refresh current page
this.refresh = function(row) {
- searchDisplayUtils.getResults(ctrl);
- };
-
- function onChangeFilters() {
- ctrl.page = 1;
- ctrl.rowCount = null;
ctrl.getResults();
- }
-
- this.formatFieldValue = function(rowData, col) {
- return searchDisplayUtils.formatDisplayValue(rowData, col.key, ctrl.settings.columns);
- };
-
- this.replaceTokens = function(value, row, raw) {
- return searchDisplayUtils.replaceTokens(value, row, raw ? null : ctrl.settings.columns);
- };
-
- this.getLinks = function(rowData, col) {
- rowData._links = rowData._links || {};
- if (!(col.key in rowData._links)) {
- rowData._links[col.key] = searchDisplayUtils.formatLinks(rowData, col.key, ctrl.settings.columns);
- }
- return rowData._links[col.key];
};
}
<li ng-repeat="(rowIndex, row) in $ctrl.results">
- <div ng-repeat="col in $ctrl.settings.columns" title="{{:: displayUtils.replaceTokens(col.title, row, $ctrl.settings.columns) }}" class="{{:: col.break ? '' : 'crm-inline-block' }}">
+ <div ng-repeat="col in $ctrl.settings.columns" title="{{:: $ctrl.replaceTokens(col.title, row) }}" class="{{:: col.break ? '' : 'crm-inline-block' }}">
<label ng-if=":: col.label && (col.type !== 'field' || col.forceLabel || row[col.key])">
- {{:: displayUtils.replaceTokens(col.label, row, $ctrl.settings.columns) }}
+ {{:: $ctrl.replaceTokens(col.label, row) }}
</label>
<span ng-include="'~/crmSearchDisplay/colType/' + col.type + '.html'"></span>
</div>
afFieldset: '?^^afFieldset'
},
templateUrl: '~/crmSearchDisplayTable/crmSearchDisplayTable.html',
- controller: function($scope, $element, crmApi4, searchDisplayUtils) {
+ controller: function($scope, $element, crmApi4, searchDisplayBaseTrait) {
var ts = $scope.ts = CRM.ts('org.civicrm.search_kit'),
- ctrl = this;
+ // Mix in properties of searchDisplayBaseTrait
+ ctrl = angular.extend(this, searchDisplayBaseTrait);
- this.page = 1;
- this.rowCount = null;
this.selectedRows = [];
this.allRowsSelected = false;
this.$onInit = function() {
- this.sort = this.settings.sort ? _.cloneDeep(this.settings.sort) : [];
- $scope.displayUtils = searchDisplayUtils;
-
- // If search is embedded in contact summary tab, display count in tab-header
- var contactTab = $element.closest('.crm-contact-page .ui-tabs-panel').attr('id');
- if (contactTab) {
- var unwatchCount = $scope.$watch('$ctrl.rowCount', function(rowCount) {
- if (typeof rowCount === 'number') {
- unwatchCount();
- CRM.tabHeader.updateCount(contactTab.replace('contact-', '#tab_'), rowCount);
- }
- });
- }
-
- if (this.afFieldset) {
- $scope.$watch(this.afFieldset.getFieldData, onChangeFilters, true);
- }
- $scope.$watch('$ctrl.filters', onChangeFilters, true);
+ this.initializeDisplay($scope, $element);
};
- this.getResults = _.debounce(function() {
- searchDisplayUtils.getResults(ctrl);
- }, 100);
-
// Refresh page after inline-editing a row
this.refresh = function(row) {
var rowId = row.id;
- searchDisplayUtils.getResults(ctrl)
+ ctrl.getResults()
.then(function() {
// If edited row disappears (because edits cause it to not meet search criteria), deselect it
var index = ctrl.selectedRows.indexOf(rowId);
});
};
- function onChangeFilters() {
- ctrl.page = 1;
- ctrl.rowCount = null;
+ this.onChangeFilters = function() {
ctrl.selectedRows.legth = 0;
ctrl.allRowsSelected = false;
- ctrl.getResults();
- }
+ };
/**
* Returns crm-i icon class for a sortable column
} else {
ctrl.sort.push([col.key, dir]);
}
- ctrl.getResults();
- };
-
- this.formatFieldValue = function(rowData, col) {
- return searchDisplayUtils.formatDisplayValue(rowData, col.key, ctrl.settings.columns);
- };
-
- this.replaceTokens = function(value, row, raw) {
- return searchDisplayUtils.replaceTokens(value, row, raw ? null : ctrl.settings.columns);
- };
-
- this.getLinks = function(rowData, col) {
- rowData._links = rowData._links || {};
- if (!(col.key in rowData._links)) {
- rowData._links[col.key] = searchDisplayUtils.formatLinks(rowData, col.key, ctrl.settings.columns);
- }
- return rowData._links[col.key];
+ $scope.getResults();
};
$scope.selectAllRows = function() {
}
// If more than one page of results, use ajax to fetch all ids
$scope.loadingAllRows = true;
- var params = searchDisplayUtils.getApiParams(ctrl, 'id');
+ var params = ctrl.getApiParams('id');
crmApi4('SearchDisplay', 'run', params, ['id']).then(function(ids) {
$scope.loadingAllRows = false;
ctrl.selectedRows = _.toArray(ids);
<div class="crm-search-display crm-search-display-table">
<div class="form-inline" ng-if="$ctrl.settings.actions">
- <crm-search-tasks entity="$ctrl.apiEntity" ids="$ctrl.selectedRows" refresh="$ctrl.getResults()"></crm-search-tasks>
+ <crm-search-tasks entity="$ctrl.apiEntity" ids="$ctrl.selectedRows" refresh="getResults()"></crm-search-tasks>
</div>
<table>
<thead>
<td ng-if=":: $ctrl.settings.actions">
<input type="checkbox" ng-checked="isRowSelected(row)" ng-click="selectRow(row)" ng-disabled="!(!loadingAllRows && row.id)">
</td>
- <td ng-repeat="col in $ctrl.settings.columns" ng-include="'~/crmSearchDisplay/colType/' + col.type + '.html'" title="{{:: displayUtils.replaceTokens(col.title, row, $ctrl.settings.columns) }}" class="{{:: col.alignment }}">
+ <td ng-repeat="col in $ctrl.settings.columns" ng-include="'~/crmSearchDisplay/colType/' + col.type + '.html'" title="{{:: $ctrl.replaceTokens(col.title, row) }}" class="{{:: col.alignment }}">
</td>
<td></td>
</tr>