Search ext: Add searchDisplay and searchPage modules
[civicrm-core.git] / ext / search / ang / searchAdmin.module.js
CommitLineData
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._);