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