Merge pull request #18464 from eileenmcnaughton/urlparamms
[civicrm-core.git] / ext / search / ang / search.module.js
1 (function(angular, $, _) {
2 "use strict";
3
4 // Shared between router and searchMeta service
5 var searchEntity,
6 // For loading saved search
7 savedSearch,
8 undefined;
9
10 // Declare module and route/controller/services
11 angular.module('search', CRM.angRequires('search'))
12
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,
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,
23 params = $route.current.params;
24 savedSearch = undefined;
25 switch (params.mode) {
26 case 'create':
27 return retrievedSearch;
28
29 case 'load':
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;
33 }
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) {
38 savedSearch = {
39 type: params.entity,
40 id: retrieved.id,
41 title: retrieved.title,
42 saved_search_id: retrieved.saved_search_id,
43 api_params: retrieved['saved_search.api_params']
44 };
45 $timeout(function() {
46 $location.url('/create/' + retrieved['saved_search.api_entity']);
47 });
48 });
49 }
50 }
51 }
52 });
53 })
54
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;
60 $scope.$ctrl = this;
61
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);
66 }
67 });
68 })
69
70 .factory('searchMeta', function() {
71 function getEntity(entityName) {
72 if (entityName) {
73 entityName = entityName === true ? searchEntity : entityName;
74 return _.find(CRM.vars.search.schema, {name: entityName});
75 }
76 }
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;
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) {
89 var field = _.find(getEntity(true).fields, {name: dotSplit[0] + '.' + fieldName});
90 if (field) {
91 return field;
92 }
93 }
94 if (joinEntity) {
95 entityName = _.find(CRM.vars.search.links[entityName], {alias: joinEntity}).entity;
96 }
97 return _.find(getEntity(entityName).fields, {name: fieldName});
98 }
99 return {
100 getEntity: getEntity,
101 getField: getField,
102 parseExpr: function(expr) {
103 var result = {},
104 fieldName = 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)});
109 }
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];
116 return result;
117 }
118 };
119 })
120
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]};
127 if (extra) {
128 _.merge(formatted, _.pick(item, extra));
129 }
130 result.push(formatted);
131 }, []);
132 };
133 });
134
135 })(angular, CRM.$, CRM._);