1 (function(angular
, $, _
) {
4 // Shared between router and searchMeta service
6 // For loading saved search
10 // Declare module and route/controller/services
11 angular
.module('search', CRM
.angRequires('search'))
13 .config(function($routeProvider
) {
14 $routeProvider
.when('/:mode/:entity/:name?', {
15 controller
: 'searchRoute',
16 template
: '<div id="bootstrap-theme" class="crm-search"><crm-search ng-if="$ctrl.mode === \'create\'" entity="$ctrl.entity" load=":: $ctrl.savedSearch"></crm-search></div>',
17 reloadOnSearch
: false,
19 // For paths like /load/Group/MySmartGroup, load the group, stash it in the savedSearch variable, and then redirect
20 // For paths like /create/Contact, return the stashed savedSearch if present
21 savedSearch: function($route
, $location
, $timeout
, crmApi4
) {
22 var retrievedSearch
= savedSearch
,
23 params
= $route
.current
.params
;
24 savedSearch
= undefined;
25 switch (params
.mode
) {
27 return retrievedSearch
;
30 // In theory savedSearches could be attached to something other than groups, but for now that's not supported
31 if (params
.entity
!== 'Group' || !params
.name
) {
32 throw 'Failed to load ' + params
.entity
;
34 return crmApi4(params
.entity
, 'get', {
35 select
: ['id', 'title', 'saved_search_id', 'saved_search.api_entity', 'saved_search.api_params'],
36 where
: [['name', '=', params
.name
]]
37 }, 0).then(function(retrieved
) {
41 title
: retrieved
.title
,
42 saved_search_id
: retrieved
.saved_search_id
,
43 api_params
: retrieved
['saved_search.api_params']
46 $location
.url('/create/' + retrieved
['saved_search.api_entity']);
55 // Controller binds entity to route
56 .controller('searchRoute', function($scope
, $routeParams
, $location
, savedSearch
) {
57 searchEntity
= this.entity
= $routeParams
.entity
;
58 this.mode
= $routeParams
.mode
;
59 this.savedSearch
= savedSearch
;
62 // Changing entity will refresh the angular page
63 $scope
.$watch('$ctrl.entity', function(newEntity
, oldEntity
) {
64 if (newEntity
&& oldEntity
&& newEntity
!== oldEntity
) {
65 $location
.url('/create/' + newEntity
);
70 .factory('searchMeta', function() {
71 function getEntity(entityName
) {
73 entityName
= entityName
=== true ? searchEntity
: entityName
;
74 return _
.find(CRM
.vars
.search
.schema
, {name
: entityName
});
77 function getField(name
) {
78 var dotSplit
= name
.split('.'),
79 joinEntity
= dotSplit
.length
> 1 ? dotSplit
[0] : null,
80 fieldName
= _
.last(dotSplit
).split(':')[0],
81 entityName
= searchEntity
;
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) {
85 fieldName
= dotSplit
[1] + '.' + fieldName
;
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) {
89 var field
= _
.find(getEntity(true).fields
, {name
: dotSplit
[0] + '.' + fieldName
});
95 entityName
= _
.find(CRM
.vars
.search
.links
[entityName
], {alias
: joinEntity
}).entity
;
97 return _
.find(getEntity(entityName
).fields
, {name
: fieldName
});
100 getEntity
: getEntity
,
102 parseExpr: function(expr
) {
105 bracketPos
= expr
.indexOf('(');
106 if (bracketPos
>= 0) {
107 fieldName
= expr
.match(/[A-Z( _]*([\w.:]+)/)[1];
108 result
.fn
= _
.find(CRM
.vars
.search
.functions
, {name
: expr
.substring(0, bracketPos
)});
110 result
.field
= getField(fieldName
);
111 var split
= fieldName
.split(':'),
112 prefixPos
= split
[0].lastIndexOf(result
.field
.name
);
113 result
.path
= split
[0];
114 result
.prefix
= prefixPos
> 0 ? result
.path
.substring(0, prefixPos
) : '';
115 result
.suffix
= !split
[1] ? '' : ':' + split
[1];
121 // Reformat an array of objects for compatibility with select2
122 // Todo this probably belongs in core
123 .factory('formatForSelect2', function() {
124 return function(input
, key
, label
, extra
) {
125 return _
.transform(input
, function(result
, item
) {
126 var formatted
= {id
: item
[key
], text
: item
[label
]};
128 _
.merge(formatted
, _
.pick(item
, extra
));
130 result
.push(formatted
);
135 })(angular
, CRM
.$, CRM
._
);