Commit | Line | Data |
---|---|---|
25523059 CW |
1 | (function(angular, $, _) { |
2 | "use strict"; | |
3 | ||
4 | // Shared between router and searchMeta service | |
2c7e2f4b CW |
5 | var searchEntity, |
6 | // For loading saved search | |
7 | savedSearch, | |
8 | undefined; | |
25523059 CW |
9 | |
10 | // Declare module and route/controller/services | |
e78d6a2d | 11 | angular.module('searchAdmin', CRM.angRequires('searchAdmin')) |
25523059 CW |
12 | |
13 | .config(function($routeProvider) { | |
2c7e2f4b | 14 | $routeProvider.when('/:mode/:entity/:name?', { |
25523059 | 15 | controller: 'searchRoute', |
2c7e2f4b CW |
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, | |
18 | resolve: { | |
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, | |
484d8c18 | 23 | getParams, |
2c7e2f4b CW |
24 | params = $route.current.params; |
25 | savedSearch = undefined; | |
26 | switch (params.mode) { | |
27 | case 'create': | |
28 | return retrievedSearch; | |
29 | ||
30 | case 'load': | |
484d8c18 CW |
31 | // Load savedSearch by `id` (the SavedSearch entity doesn't have `name`) |
32 | if (params.entity === 'SavedSearch' && /^\d+$/.test(params.name)) { | |
33 | getParams = { | |
34 | where: [['id', '=', params.name]] | |
35 | }; | |
36 | } | |
37 | // Load attached entity (e.g. Smart Groups) with a join via saved_search_id | |
38 | else if (params.entity === 'Group' && params.name) { | |
39 | getParams = { | |
40 | select: ['id', 'title', 'saved_search_id', 'saved_search.*'], | |
41 | where: [['name', '=', params.name]] | |
42 | }; | |
43 | } | |
2c7e2f4b | 44 | // In theory savedSearches could be attached to something other than groups, but for now that's not supported |
484d8c18 | 45 | else { |
2c7e2f4b CW |
46 | throw 'Failed to load ' + params.entity; |
47 | } | |
484d8c18 CW |
48 | return crmApi4(params.entity, 'get', getParams, 0).then(function(retrieved) { |
49 | savedSearch = retrieved; | |
50 | savedSearch.type = params.entity; | |
51 | if (params.entity !== 'SavedSearch') { | |
52 | savedSearch.api_entity = retrieved['saved_search.api_entity']; | |
53 | savedSearch.api_params = retrieved['saved_search.api_params']; | |
54 | savedSearch.form_values = retrieved['saved_search.form_values']; | |
55 | } | |
2c7e2f4b | 56 | $timeout(function() { |
484d8c18 | 57 | $location.url('/create/' + savedSearch.api_entity); |
2c7e2f4b CW |
58 | }); |
59 | }); | |
60 | } | |
61 | } | |
62 | } | |
25523059 CW |
63 | }); |
64 | }) | |
65 | ||
66 | // Controller binds entity to route | |
2c7e2f4b CW |
67 | .controller('searchRoute', function($scope, $routeParams, $location, savedSearch) { |
68 | searchEntity = this.entity = $routeParams.entity; | |
69 | this.mode = $routeParams.mode; | |
70 | this.savedSearch = savedSearch; | |
71 | $scope.$ctrl = this; | |
25523059 CW |
72 | |
73 | // Changing entity will refresh the angular page | |
2c7e2f4b | 74 | $scope.$watch('$ctrl.entity', function(newEntity, oldEntity) { |
25523059 | 75 | if (newEntity && oldEntity && newEntity !== oldEntity) { |
2c7e2f4b | 76 | $location.url('/create/' + newEntity); |
25523059 CW |
77 | } |
78 | }); | |
79 | }) | |
80 | ||
81 | .factory('searchMeta', function() { | |
82 | function getEntity(entityName) { | |
83 | if (entityName) { | |
25523059 CW |
84 | return _.find(CRM.vars.search.schema, {name: entityName}); |
85 | } | |
86 | } | |
c419e6ed CW |
87 | function getField(fieldName, entityName) { |
88 | var dotSplit = fieldName.split('.'), | |
25523059 | 89 | joinEntity = dotSplit.length > 1 ? dotSplit[0] : null, |
c419e6ed | 90 | name = _.last(dotSplit).split(':')[0]; |
27bed3cb CW |
91 | // Custom fields contain a dot in their fieldname |
92 | // If 3 segments, the first is the joinEntity and the last 2 are the custom field | |
93 | if (dotSplit.length === 3) { | |
c419e6ed | 94 | name = dotSplit[1] + '.' + name; |
27bed3cb CW |
95 | } |
96 | // If 2 segments, it's ambiguous whether this is a custom field or joined field. Search the main entity first. | |
97 | if (dotSplit.length === 2) { | |
c419e6ed | 98 | var field = _.find(getEntity(entityName).fields, {name: dotSplit[0] + '.' + name}); |
27bed3cb CW |
99 | if (field) { |
100 | return field; | |
101 | } | |
102 | } | |
25523059 CW |
103 | if (joinEntity) { |
104 | entityName = _.find(CRM.vars.search.links[entityName], {alias: joinEntity}).entity; | |
105 | } | |
c419e6ed | 106 | return _.find(getEntity(entityName).fields, {name: name}); |
25523059 CW |
107 | } |
108 | return { | |
109 | getEntity: getEntity, | |
110 | getField: getField, | |
111 | parseExpr: function(expr) { | |
f99d41d2 | 112 | var result = {fn: null, modifier: ''}, |
25523059 CW |
113 | fieldName = expr, |
114 | bracketPos = expr.indexOf('('); | |
115 | if (bracketPos >= 0) { | |
f99d41d2 CW |
116 | var parsed = expr.substr(bracketPos).match(/[ ]?([A-Z]+[ ]+)?([\w.:]+)/); |
117 | fieldName = parsed[2]; | |
22601c92 | 118 | result.fn = _.find(CRM.searchAdmin.functions, {name: expr.substring(0, bracketPos)}); |
f99d41d2 | 119 | result.modifier = _.trim(parsed[1]); |
25523059 | 120 | } |
c419e6ed CW |
121 | result.field = expr ? getField(fieldName, searchEntity) : undefined; |
122 | if (result.field) { | |
123 | var split = fieldName.split(':'), | |
124 | prefixPos = split[0].lastIndexOf(result.field.name); | |
125 | result.path = split[0]; | |
126 | result.prefix = prefixPos > 0 ? result.path.substring(0, prefixPos) : ''; | |
127 | result.suffix = !split[1] ? '' : ':' + split[1]; | |
128 | } | |
25523059 CW |
129 | return result; |
130 | } | |
131 | }; | |
132 | }) | |
133 | ||
134 | // Reformat an array of objects for compatibility with select2 | |
135 | // Todo this probably belongs in core | |
136 | .factory('formatForSelect2', function() { | |
137 | return function(input, key, label, extra) { | |
138 | return _.transform(input, function(result, item) { | |
139 | var formatted = {id: item[key], text: item[label]}; | |
140 | if (extra) { | |
141 | _.merge(formatted, _.pick(item, extra)); | |
142 | } | |
143 | result.push(formatted); | |
144 | }, []); | |
145 | }; | |
146 | }); | |
147 | ||
148 | })(angular, CRM.$, CRM._); |