Collapse columns to save space.
Split addColMenu in two, allows toggling multiple columns at once.
controller: function($scope, $timeout, searchMeta) {
var ts = $scope.ts = CRM.ts('org.civicrm.search_kit'),
ctrl = this;
+ let initDefaults;
this.isSuperAdmin = CRM.checkPerm('all CiviCRM permissions and ACLs');
this.aclBypassHelp = ts('Only users with "all CiviCRM permissions and ACLs" can disable permission checks.');
this.styles = CRM.crmSearchAdmin.styles;
+ function selectToKey(selectExpr) {
+ return selectExpr.split(' AS ').slice(-1)[0];
+ }
+
this.addCol = function(type) {
var col = _.cloneDeep(this.colTypes[type].defaults);
col.type = type;
};
this.removeCol = function(index) {
- if (ctrl.display.settings.columns[index].type === 'field') {
- ctrl.hiddenColumns.push(ctrl.display.settings.columns[index]);
- }
ctrl.display.settings.columns.splice(index, 1);
};
- this.restoreCol = function(index) {
- ctrl.display.settings.columns.push(ctrl.hiddenColumns[index]);
- ctrl.hiddenColumns.splice(index, 1);
+ this.getColumnIndex = function(key) {
+ key = selectToKey(key);
+ return ctrl.display.settings.columns.findIndex(col => key === col.key);
+ };
+
+ this.columnExists = function(key) {
+ return ctrl.getColumnIndex(key) > -1;
+ };
+
+ this.toggleColumn = function(key) {
+ let index = ctrl.getColumnIndex(key);
+ if (index > -1) {
+ ctrl.removeCol(index);
+ } else {
+ ctrl.display.settings.columns.push(searchMeta.fieldToColumn(key, initDefaults));
+ }
};
this.getExprFromSelect = function(key) {
};
this.getFieldLabel = function(key) {
- var expr = ctrl.getExprFromSelect(key);
+ var expr = ctrl.getExprFromSelect(selectToKey(key));
return searchMeta.getDefaultLabel(expr);
};
// Helper function to sort active from hidden columns and initialize each column with defaults
this.initColumns = function(defaults) {
+ initDefaults = defaults;
if (!ctrl.display.settings.columns) {
ctrl.display.settings.columns = _.transform(ctrl.savedSearch.api_params.select, function(columns, fieldExpr) {
columns.push(searchMeta.fieldToColumn(fieldExpr, defaults));
});
- ctrl.hiddenColumns = [];
} else {
- var activeColumns = _.collect(ctrl.display.settings.columns, 'key'),
- selectAliases = _.map(ctrl.savedSearch.api_params.select, function(select) {
- return _.last(select.split(' AS '));
- });
- ctrl.hiddenColumns = _.transform(ctrl.savedSearch.api_params.select, function(hiddenColumns, fieldExpr) {
- var key = _.last(fieldExpr.split(' AS '));
- if (!_.includes(activeColumns, key)) {
- hiddenColumns.push(searchMeta.fieldToColumn(fieldExpr, defaults));
- }
- });
- _.eachRight(activeColumns, function(key, index) {
+ let activeColumns = ctrl.display.settings.columns.map(col => col.key);
+ let selectAliases = ctrl.savedSearch.api_params.select.map(selectExpr => selectToKey(selectExpr));
+ // Delete any column that is no longer in the
+ activeColumns.reverse().forEach((key, index) => {
if (key && !_.includes(selectAliases, key)) {
ctrl.display.settings.columns.splice(index, 1);
}
<i class="crm-i fa-arrows crm-search-move-icon"></i>
<crm-search-function ng-if="!col.isPseudoField" class="form-inline" mode="select" expr="col.key"></crm-search-function>
<label ng-if="col.isPseudoField">{{:: col.label }}</label>
- <button type="button" class="btn-xs pull-right" ng-if="$ctrl.select.length > 1" ng-click="$ctrl.crmSearchAdmin.clearParam('select', $index)" title="{{:: ts('Remove') }}">
+ <button type="button" class="btn btn-xs pull-right" ng-if="$ctrl.select.length > 1" ng-click="$ctrl.crmSearchAdmin.clearParam('select', $index)" title="{{:: ts('Remove') }}">
<i class="crm-i fa-ban"></i>
</button>
</fieldset>
-<button type="button" class="btn dropdown-toggle btn-secondary-outline" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
- <i class="crm-i fa-plus"></i>
- {{:: ts('Add') }} <span class="caret"></span>
-</button>
-<ul class="dropdown-menu">
- <li ng-repeat="(type, col) in $ctrl.getColTypes()">
- <a href ng-click="$ctrl.parent.addCol(type)"><i class="fa {{:: col.icon }}"></i> {{:: col.label }}</a>
- </li>
- <li class="divider" ng-show="$ctrl.parent.hiddenColumns.length && $ctrl.getColTypes().length"></li>
- <li ng-repeat="col in $ctrl.parent.hiddenColumns">
- <a href ng-click="$ctrl.parent.restoreCol($index)">
- {{:: $ctrl.parent.getFieldLabel(col.key) }}
- </a>
- </li>
-</ul>
+<div class="btn-group">
+ <button type="button" class="btn dropdown-toggle btn-primary" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
+ <i class="crm-i fa-plus-square-o"></i>
+ {{:: ts('Add/Remove Fields') }} <span class="caret"></span>
+ </button>
+ <ul class="dropdown-menu">
+ <li ng-repeat="item in $ctrl.parent.savedSearch.api_params.select track by $index">
+ <a href ng-click="$ctrl.parent.toggleColumn(item); $event.stopPropagation()">
+ <i class="crm-i fa-{{ $ctrl.parent.columnExists(item) ? 'check-' : '' }}square-o"></i>
+ {{ $ctrl.parent.getFieldLabel(item) }}
+ </a>
+ </li>
+ </ul>
+</div>
+<div class="btn-group" ng-if="$ctrl.getColTypes">
+ <button type="button" class="btn dropdown-toggle btn-primary" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
+ <i class="crm-i fa-link"></i>
+ {{:: ts('Add Links, etc.') }} <span class="caret"></span>
+ </button>
+ <ul class="dropdown-menu">
+ <li ng-repeat="(type, col) in $ctrl.getColTypes()">
+ <a href ng-click="$ctrl.parent.addCol(type)">
+ <i class="crm-i {{:: col.icon }}"></i>
+ {{:: col.label }}
+ </a>
+ </li>
+ </ul>
+</div>
templateUrl: '~/crmSearchAdmin/displays/searchAdminDisplayAutocomplete.html',
controller: function($scope, searchMeta) {
var ts = $scope.ts = CRM.ts('org.civicrm.search_kit'),
- ctrl = this,
- colTypes = [];
-
- this.getColTypes = function() {
- return colTypes;
- };
+ ctrl = this;
this.$onInit = function () {
if (!ctrl.display.settings) {
<fieldset class="crm-search-admin-edit-columns-wrapper">
<legend>
{{:: ts('Fields') }}
- <div ng-if="$ctrl.parent.hiddenColumns.length" ng-include="'~/crmSearchAdmin/displays/common/addColMenu.html'" class="btn-group btn-group-xs"></div>
</legend>
+ <div ng-include="'~/crmSearchAdmin/displays/common/addColMenu.html'"></div>
<p class="help-block">
{{:: ts("The top-most line will be shown as the searchable title (combine multiple fields using rewrite + tokens).") }}
{{:: ts("Other lines will be shown below in smaller text, and will not be searchable (except for ID which is always searchable).") }}
</p>
- <div class="crm-search-admin-edit-columns" ng-model="$ctrl.display.settings.columns" ui-sortable="$ctrl.parent.sortableOptions">
+ <fieldset class="crm-search-admin-edit-columns" ng-model="$ctrl.display.settings.columns" ui-sortable="$ctrl.parent.sortableOptions">
<fieldset ng-repeat="col in $ctrl.display.settings.columns" class="crm-draggable">
<legend>
<i class="crm-i fa-arrows crm-search-move-icon"></i>
</div>
<search-admin-icons item="col" ng-if="!$index"></search-admin-icons>
</fieldset>
- </div>
+ </fieldset>
</fieldset>
templateUrl: '~/crmSearchAdmin/displays/searchAdminDisplayEntity.html',
controller: function($scope, crmApi4) {
var ts = $scope.ts = CRM.ts('org.civicrm.search_kit'),
- ctrl = this,
- colTypes = [];
-
- this.getColTypes = function() {
- return colTypes;
- };
+ ctrl = this;
this.$onInit = function () {
ctrl.jobFrequency = CRM.crmSearchAdmin.jobFrequency;
<fieldset class="crm-search-admin-edit-columns-wrapper">
<legend>
{{:: ts('Columns') }}
- <div ng-if="$ctrl.parent.hiddenColumns.length" ng-include="'~/crmSearchAdmin/displays/common/addColMenu.html'" class="btn-group btn-group-xs"></div>
</legend>
- <div class="crm-search-admin-edit-columns" ng-model="$ctrl.display.settings.columns" ui-sortable="$ctrl.parent.sortableOptions">
+ <div ng-include="'~/crmSearchAdmin/displays/common/addColMenu.html'"></div>
+ <fieldset class="crm-search-admin-edit-columns" ng-model="$ctrl.display.settings.columns" ui-sortable="$ctrl.parent.sortableOptions">
<fieldset ng-repeat="col in $ctrl.display.settings.columns" class="crm-draggable">
<legend>
<i class="crm-i fa-arrows crm-search-move-icon"></i>
</button>
</div>
</fieldset>
- </div>
+ </fieldset>
</fieldset>
<fieldset class="crm-search-admin-edit-columns-wrapper">
<legend>
{{:: ts('Fields') }}
- <div ng-include="'~/crmSearchAdmin/displays/common/addColMenu.html'" class="btn-group btn-group-xs"></div>
</legend>
- <div class="crm-search-admin-edit-columns" ng-model="$ctrl.display.settings.columns" ui-sortable="$ctrl.parent.sortableOptions">
+ <div ng-include="'~/crmSearchAdmin/displays/common/addColMenu.html'"></div>
+ <fieldset class="crm-search-admin-edit-columns" ng-model="$ctrl.display.settings.columns" ui-sortable="$ctrl.parent.sortableOptions">
<fieldset ng-repeat="col in $ctrl.display.settings.columns" class="crm-draggable">
- <legend><i class="crm-i fa-arrows crm-search-move-icon"></i> {{ $ctrl.parent.getColLabel(col) }}</legend>
- <div class="form-inline" title="{{:: ts('Should this item display on its own line or inline with other items?') }}">
- <label><input type="checkbox" ng-model="col.break"> {{:: ts('New Line') }}</label>
- <button type="button" class="btn-xs pull-right" ng-click="$ctrl.parent.removeCol($index)" title="{{:: ts('Remove') }}">
- <i class="crm-i fa-ban"></i>
- </button>
- </div>
- <div class="form-inline crm-search-admin-flex-row">
- <label>
- <input type="checkbox" ng-checked="col.label" ng-click="col.label = col.label ? null : $ctrl.parent.getColLabel(col)" >
- {{:: ts('Label') }}
- </label>
- <input ng-if="col.label" class="form-control crm-flex-1" type="text" ng-model="col.label" ng-model-options="{updateOn: 'blur'}">
- <crm-search-admin-token-select ng-if="col.label" model="col" field="label" suffix=":label"></crm-search-admin-token-select>
- </div>
- <div class="form-inline" ng-if="col.label">
- <label style="visibility: hidden"><input type="checkbox" disabled></label><!--To indent by 1 checkbox-width-->
- <div class="checkbox">
- <label><input type="checkbox" ng-model="col.forceLabel"> {{:: ts('Show label even when field is blank') }}</label>
+ <i class="crm-i fa-arrows crm-search-move-icon"></i>
+ <button type="button" class="btn btn-xs pull-right" ng-click="$ctrl.parent.removeCol($index)" title="{{:: ts('Remove') }}">
+ <i class="crm-i fa-ban"></i>
+ </button>
+ <details>
+ <summary> {{ $ctrl.parent.getColLabel(col) }}</summary>
+ <div class="form-inline" title="{{:: ts('Should this item display on its own line or inline with other items?') }}">
+ <label><input type="checkbox" ng-model="col.break"> {{:: ts('New Line') }}</label>
</div>
- </div>
- <div ng-include="'~/crmSearchAdmin/displays/colType/' + col.type + '.html'"></div>
+ <div class="form-inline crm-search-admin-flex-row">
+ <label>
+ <input type="checkbox" ng-checked="col.label" ng-click="col.label = col.label ? null : $ctrl.parent.getColLabel(col)" >
+ {{:: ts('Label') }}
+ </label>
+ <input ng-if="col.label" class="form-control crm-flex-1" type="text" ng-model="col.label" ng-model-options="{updateOn: 'blur'}">
+ <crm-search-admin-token-select ng-if="col.label" model="col" field="label" suffix=":label"></crm-search-admin-token-select>
+ </div>
+ <div class="form-inline" ng-if="col.label">
+ <label style="visibility: hidden"><input type="checkbox" disabled></label><!--To indent by 1 checkbox-width-->
+ <div class="checkbox">
+ <label><input type="checkbox" ng-model="col.forceLabel"> {{:: ts('Show label even when field is blank') }}</label>
+ </div>
+ </div>
+ <div ng-include="'~/crmSearchAdmin/displays/colType/' + col.type + '.html'"></div>
+ </details>
</fieldset>
- </div>
+ </fieldset>
</fieldset>
<fieldset class="crm-search-admin-edit-columns-wrapper">
<legend>
{{:: ts('Fields') }}
- <div ng-include="'~/crmSearchAdmin/displays/common/addColMenu.html'" class="btn-group btn-group-xs"></div>
</legend>
- <div class="crm-search-admin-edit-columns" ng-model="$ctrl.display.settings.columns" ui-sortable="$ctrl.parent.sortableOptions">
+ <div ng-include="'~/crmSearchAdmin/displays/common/addColMenu.html'"></div>
+ <fieldset class="crm-search-admin-edit-columns" ng-model="$ctrl.display.settings.columns" ui-sortable="$ctrl.parent.sortableOptions">
<fieldset ng-repeat="col in $ctrl.display.settings.columns" class="crm-draggable">
- <legend><i class="crm-i fa-arrows crm-search-move-icon"></i> {{ $ctrl.parent.getColLabel(col) }}</legend>
- <div class="form-inline" title="{{:: ts('Should this item display on its own line or inline with other items?') }}">
- <label><input type="checkbox" ng-model="col.break"> {{:: ts('New Line') }}</label>
- <button type="button" class="btn-xs pull-right" ng-click="$ctrl.parent.removeCol($index)" title="{{:: ts('Remove') }}">
- <i class="crm-i fa-ban"></i>
- </button>
- </div>
- <div class="form-inline crm-search-admin-flex-row">
- <label>
- <input type="checkbox" ng-checked="col.label" ng-click="col.label = col.label ? null : $ctrl.parent.getColLabel(col)" >
- {{:: ts('Label') }}
- </label>
- <input ng-if="col.label" class="form-control crm-flex-1" type="text" ng-model="col.label" ng-model-options="{updateOn: 'blur'}">
- <crm-search-admin-token-select ng-if="col.label" model="col" field="label" suffix=":label"></crm-search-admin-token-select>
- </div>
- <div class="form-inline" ng-if="col.label">
- <label style="visibility: hidden"><input type="checkbox" disabled></label><!--To indent by 1 checkbox-width-->
- <div class="checkbox">
- <label><input type="checkbox" ng-model="col.forceLabel"> {{:: ts('Show label even when field is blank') }}</label>
+ <i class="crm-i fa-arrows crm-search-move-icon"></i>
+ <button type="button" class="btn btn-xs pull-right" ng-click="$ctrl.parent.removeCol($index)" title="{{:: ts('Remove') }}">
+ <i class="crm-i fa-ban"></i>
+ </button>
+ <details>
+ <summary>{{ $ctrl.parent.getColLabel(col) }}</summary>
+ <div class="form-inline" title="{{:: ts('Should this item display on its own line or inline with other items?') }}">
+ <label><input type="checkbox" ng-model="col.break"> {{:: ts('New Line') }}</label>
</div>
- </div>
- <div ng-include="'~/crmSearchAdmin/displays/colType/' + col.type + '.html'"></div>
+ <div class="form-inline crm-search-admin-flex-row">
+ <label>
+ <input type="checkbox" ng-checked="col.label" ng-click="col.label = col.label ? null : $ctrl.parent.getColLabel(col)" >
+ {{:: ts('Label') }}
+ </label>
+ <input ng-if="col.label" class="form-control crm-flex-1" type="text" ng-model="col.label" ng-model-options="{updateOn: 'blur'}">
+ <crm-search-admin-token-select ng-if="col.label" model="col" field="label" suffix=":label"></crm-search-admin-token-select>
+ </div>
+ <div class="form-inline" ng-if="col.label">
+ <label style="visibility: hidden"><input type="checkbox" disabled></label><!--To indent by 1 checkbox-width-->
+ <div class="checkbox">
+ <label><input type="checkbox" ng-model="col.forceLabel"> {{:: ts('Show label even when field is blank') }}</label>
+ </div>
+ </div>
+ <div ng-include="'~/crmSearchAdmin/displays/colType/' + col.type + '.html'"></div>
+ </details>
</fieldset>
- </div>
+ </fieldset>
</fieldset>
<fieldset class="crm-search-admin-edit-columns-wrapper">
<legend>
{{:: ts('Columns') }}
- <div ng-include="'~/crmSearchAdmin/displays/common/addColMenu.html'" class="btn-group btn-group-xs"></div>
</legend>
- <div class="crm-search-admin-edit-columns" ng-model="$ctrl.display.settings.columns" ui-sortable="$ctrl.parent.sortableOptions">
+ <div ng-include="'~/crmSearchAdmin/displays/common/addColMenu.html'"></div>
+ <fieldset class="crm-search-admin-edit-columns" ng-model="$ctrl.display.settings.columns" ui-sortable="$ctrl.parent.sortableOptions">
<fieldset ng-repeat="col in $ctrl.display.settings.columns" class="crm-draggable">
- <legend><i class="crm-i fa-arrows crm-search-move-icon"></i> {{ $ctrl.parent.getColLabel(col) }}</legend>
- <div class="form-inline crm-search-admin-flex-row">
- <label for="crm-search-admin-edit-col-{{ $index }}">{{:: ts('Header') }}</label>
- <input id="crm-search-admin-edit-col-{{ $index }}" class="form-control crm-flex-1" type="text" ng-model="col.label" >
- <button type="button" class="btn-xs" ng-click="$ctrl.parent.removeCol($index)" title="{{:: ts('Remove') }}">
- <i class="crm-i fa-ban"></i>
- </button>
- </div>
- <div class="form-inline">
- <label>{{:: ts('Alignment') }}</label>
- <select ng-model="col.alignment" class="form-control">
- <option value="">{{:: ts('Left') }}</option>
- <option value="text-center">{{:: ts('Center') }}</option>
- <option value="text-right">{{:: ts('Right') }}</option>
- </select>
- </div>
- <div class="form-inline" ng-if="$ctrl.parent.canBeSortable(col)">
- <label title="{{:: ts('Allow user to click on header to sort table by this column') }}">
- <input type="checkbox" ng-checked="col.sortable !== false" ng-click="col.sortable = col.sortable === false" >
- {{:: ts('Sortable Header') }}
- </label>
- </div>
- <div ng-include="'~/crmSearchAdmin/displays/colType/' + col.type + '.html'"></div>
- <div class="form-inline" ng-if="col.type === 'field' && $ctrl.display.settings.tally">
- <label>{{:: ts('Footer Label') }}</label>
- <input class="form-control" ng-model="col.tally.label" placeholder="{{:: ts('None') }}">
- <label>{{:: ts('Footer Aggregate') }}</label>
- <input class="form-control" ng-model="col.tally.fn" crm-ui-select="{data: $ctrl.getTallyFunctions, placeholder: ts('None'), allowClear: true}">
- </div>
+ <i class="crm-i fa-arrows crm-search-move-icon"></i>
+ <button type="button" class="btn btn-xs pull-right" ng-click="$ctrl.parent.removeCol($index)" title="{{:: ts('Remove') }}">
+ <i class="crm-i fa-ban"></i>
+ </button>
+ <details>
+ <summary>{{ $ctrl.parent.getColLabel(col) }}</summary>
+ <div class="form-inline crm-search-admin-flex-row">
+ <label for="crm-search-admin-edit-col-{{ $index }}">{{:: ts('Header') }}</label>
+ <input id="crm-search-admin-edit-col-{{ $index }}" class="form-control crm-flex-1" type="text" ng-model="col.label" >
+ </div>
+ <div class="form-inline">
+ <label>{{:: ts('Alignment') }}</label>
+ <select ng-model="col.alignment" class="form-control">
+ <option value="">{{:: ts('Left') }}</option>
+ <option value="text-center">{{:: ts('Center') }}</option>
+ <option value="text-right">{{:: ts('Right') }}</option>
+ </select>
+ </div>
+ <div class="form-inline" ng-if="$ctrl.parent.canBeSortable(col)">
+ <label title="{{:: ts('Allow user to click on header to sort table by this column') }}">
+ <input type="checkbox" ng-checked="col.sortable !== false" ng-click="col.sortable = col.sortable === false" >
+ {{:: ts('Sortable Header') }}
+ </label>
+ </div>
+ <div ng-include="'~/crmSearchAdmin/displays/colType/' + col.type + '.html'"></div>
+ <div class="form-inline" ng-if="col.type === 'field' && $ctrl.display.settings.tally">
+ <label>{{:: ts('Footer Label') }}</label>
+ <input class="form-control" ng-model="col.tally.label" placeholder="{{:: ts('None') }}">
+ <label>{{:: ts('Footer Aggregate') }}</label>
+ <input class="form-control" ng-model="col.tally.fn" crm-ui-select="{data: $ctrl.getTallyFunctions, placeholder: ts('None'), allowClear: true}">
+ </div>
+ </details>
</fieldset>
- </div>
+ </fieldset>
</fieldset>
right: 0;
background-color: white;
}
+
+#bootstrap-theme .crm-search-admin-edit-columns details summary {
+ font-size: inherit;
+}