Merge pull request #18819 from eileenmcnaughton/import
[civicrm-core.git] / ext / search / ang / crmSearchAdmin.module.js
1 (function(angular, $, _) {
2 "use strict";
3
4 // Shared between router and searchMeta service
5 var searchEntity,
6 undefined;
7
8 // Declare module and route/controller/services
9 angular.module('crmSearchAdmin', CRM.angRequires('crmSearchAdmin'))
10
11 .config(function($routeProvider) {
12 $routeProvider.when('/list', {
13 controller: 'searchList',
14 templateUrl: '~/crmSearchAdmin/searchList.html',
15 resolve: {
16 // Load data for lists
17 savedSearches: function(crmApi4) {
18 return crmApi4('SavedSearch', 'get', {
19 select: [
20 'id',
21 'name',
22 'label',
23 'api_entity',
24 'form_values',
25 'GROUP_CONCAT(display.name ORDER BY display.id) AS display_name',
26 'GROUP_CONCAT(display.label ORDER BY display.id) AS display_label',
27 'GROUP_CONCAT(display.type:icon ORDER BY display.id) AS display_icon',
28 'GROUP_CONCAT(group.title) AS groups'
29 ],
30 join: [['SearchDisplay AS display'], ['Group AS group']],
31 where: [['api_entity', 'IS NOT NULL']],
32 groupBy: ['id']
33 });
34 }
35 }
36 });
37 $routeProvider.when('/create/:entity', {
38 controller: 'searchCreate',
39 template: '<crm-search-admin saved-search="$ctrl.savedSearch"></crm-search-admin>',
40 });
41 $routeProvider.when('/edit/:id', {
42 controller: 'searchEdit',
43 template: '<crm-search-admin saved-search="$ctrl.savedSearch"></crm-search-admin>',
44 resolve: {
45 // Load saved search
46 savedSearch: function($route, crmApi4) {
47 var params = $route.current.params;
48 return crmApi4('SavedSearch', 'get', {
49 where: [['id', '=', params.id]],
50 chain: {
51 groups: ['Group', 'get', {select: ['id', 'title', 'description', 'visibility', 'group_type'], where: [['saved_search_id', '=', '$id']]}],
52 displays: ['SearchDisplay', 'get', {where: [['saved_search_id', '=', '$id']]}]
53 }
54 }, 0);
55 }
56 }
57 });
58 })
59
60 // Controller for creating a new search
61 .controller('searchCreate', function($scope, $routeParams, $location) {
62 searchEntity = $routeParams.entity;
63 $scope.$ctrl = this;
64 this.savedSearch = {
65 api_entity: searchEntity,
66 };
67 // Changing entity will refresh the angular page
68 $scope.$watch('$ctrl.savedSearch.api_entity', function(newEntity, oldEntity) {
69 if (newEntity && oldEntity && newEntity !== oldEntity) {
70 $location.url('/create/' + newEntity);
71 }
72 });
73 })
74
75 // Controller for editing a SavedSearch
76 .controller('searchEdit', function($scope, savedSearch) {
77 searchEntity = savedSearch.api_entity;
78 this.savedSearch = savedSearch;
79 $scope.$ctrl = this;
80 })
81
82 .factory('searchMeta', function() {
83 function getEntity(entityName) {
84 if (entityName) {
85 return _.find(CRM.vars.search.schema, {name: entityName});
86 }
87 }
88 function getField(fieldName, entityName) {
89 var dotSplit = fieldName.split('.'),
90 joinEntity = dotSplit.length > 1 ? dotSplit[0] : null,
91 name = _.last(dotSplit).split(':')[0],
92 field;
93 // Custom fields contain a dot in their fieldname
94 // If 3 segments, the first is the joinEntity and the last 2 are the custom field
95 if (dotSplit.length === 3) {
96 name = dotSplit[1] + '.' + name;
97 }
98 // If 2 segments, it's ambiguous whether this is a custom field or joined field. Search the main entity first.
99 if (dotSplit.length === 2) {
100 field = _.find(getEntity(entityName).fields, {name: dotSplit[0] + '.' + name});
101 if (field) {
102 field.entity = entityName;
103 return field;
104 }
105 }
106 if (joinEntity) {
107 entityName = _.find(CRM.vars.search.links[entityName], {alias: joinEntity}).entity;
108 }
109 field = _.find(getEntity(entityName).fields, {name: name});
110 if (field) {
111 field.entity = entityName;
112 return field;
113 }
114 }
115 return {
116 getEntity: getEntity,
117 getField: getField,
118 parseExpr: function(expr) {
119 var result = {fn: null, modifier: ''},
120 fieldName = expr,
121 bracketPos = expr.indexOf('(');
122 if (bracketPos >= 0) {
123 var parsed = expr.substr(bracketPos).match(/[ ]?([A-Z]+[ ]+)?([\w.:]+)/);
124 fieldName = parsed[2];
125 result.fn = _.find(CRM.crmSearchAdmin.functions, {name: expr.substring(0, bracketPos)});
126 result.modifier = _.trim(parsed[1]);
127 }
128 result.field = expr ? getField(fieldName, searchEntity) : undefined;
129 if (result.field) {
130 var split = fieldName.split(':'),
131 prefixPos = split[0].lastIndexOf(result.field.name);
132 result.path = split[0];
133 result.prefix = prefixPos > 0 ? result.path.substring(0, prefixPos) : '';
134 result.suffix = !split[1] ? '' : ':' + split[1];
135 }
136 return result;
137 },
138 // Find all possible search columns that could serve as contact_id for a smart group
139 getSmartGroupColumns: function(api_entity, api_params) {
140 var joins = _.pluck((api_params.join || []), 0),
141 entityCount = {};
142 return _.transform([api_entity].concat(joins), function(columns, joinExpr) {
143 var joinName = joinExpr.split(' AS '),
144 entityName = joinName[0],
145 entity = getEntity(entityName),
146 prefix = joinName[1] ? joinName[1] + '.' : '';
147 _.each(entity.fields, function(field) {
148 if ((entityName === 'Contact' && field.name === 'id') || field.fk_entity === 'Contact') {
149 columns.push({
150 id: prefix + field.name,
151 text: entity.title_plural + (entityCount[entityName] ? ' ' + entityCount[entityName] : '') + ': ' + field.label,
152 icon: entity.icon
153 });
154 }
155 });
156 entityCount[entityName] = 1 + (entityCount[entityName] || 1);
157 });
158 }
159 };
160 });
161
162 })(angular, CRM.$, CRM._);