"use strict";
// Shared between router and searchMeta service
- var searchEntity;
+ var searchEntity,
+ // For loading saved search
+ savedSearch,
+ undefined;
// Declare module and route/controller/services
angular.module('search', CRM.angRequires('search'))
.config(function($routeProvider) {
- $routeProvider.when('/:entity', {
+ $routeProvider.when('/:mode/:entity/:name?', {
controller: 'searchRoute',
- template: '<div id="bootstrap-theme" class="crm-search"><crm-search entity="entity"></crm-search></div>',
- reloadOnSearch: false
+ template: '<div id="bootstrap-theme" class="crm-search"><crm-search ng-if="$ctrl.mode === \'create\'" entity="$ctrl.entity" load=":: $ctrl.savedSearch"></crm-search></div>',
+ reloadOnSearch: false,
+ resolve: {
+ // For paths like /load/Group/MySmartGroup, load the group, stash it in the savedSearch variable, and then redirect
+ // For paths like /create/Contact, return the stashed savedSearch if present
+ savedSearch: function($route, $location, $timeout, crmApi4) {
+ var retrievedSearch = savedSearch,
+ getParams,
+ params = $route.current.params;
+ savedSearch = undefined;
+ switch (params.mode) {
+ case 'create':
+ return retrievedSearch;
+
+ case 'load':
+ // Load savedSearch by `id` (the SavedSearch entity doesn't have `name`)
+ if (params.entity === 'SavedSearch' && /^\d+$/.test(params.name)) {
+ getParams = {
+ where: [['id', '=', params.name]]
+ };
+ }
+ // Load attached entity (e.g. Smart Groups) with a join via saved_search_id
+ else if (params.entity === 'Group' && params.name) {
+ getParams = {
+ select: ['id', 'title', 'saved_search_id', 'saved_search.*'],
+ where: [['name', '=', params.name]]
+ };
+ }
+ // In theory savedSearches could be attached to something other than groups, but for now that's not supported
+ else {
+ throw 'Failed to load ' + params.entity;
+ }
+ return crmApi4(params.entity, 'get', getParams, 0).then(function(retrieved) {
+ savedSearch = retrieved;
+ savedSearch.type = params.entity;
+ if (params.entity !== 'SavedSearch') {
+ savedSearch.api_entity = retrieved['saved_search.api_entity'];
+ savedSearch.api_params = retrieved['saved_search.api_params'];
+ savedSearch.form_values = retrieved['saved_search.form_values'];
+ }
+ $timeout(function() {
+ $location.url('/create/' + savedSearch.api_entity);
+ });
+ });
+ }
+ }
+ }
});
})
// Controller binds entity to route
- .controller('searchRoute', function($scope, $routeParams, $location) {
- searchEntity = $scope.entity = $routeParams.entity;
+ .controller('searchRoute', function($scope, $routeParams, $location, savedSearch) {
+ searchEntity = this.entity = $routeParams.entity;
+ this.mode = $routeParams.mode;
+ this.savedSearch = savedSearch;
+ $scope.$ctrl = this;
// Changing entity will refresh the angular page
- $scope.$watch('entity', function(newEntity, oldEntity) {
+ $scope.$watch('$ctrl.entity', function(newEntity, oldEntity) {
if (newEntity && oldEntity && newEntity !== oldEntity) {
- $location.url('/' + newEntity);
+ $location.url('/create/' + newEntity);
}
});
})
.factory('searchMeta', function() {
function getEntity(entityName) {
if (entityName) {
- entityName = entityName === true ? searchEntity : entityName;
return _.find(CRM.vars.search.schema, {name: entityName});
}
}
- function getField(name) {
- var dotSplit = name.split('.'),
+ function getField(fieldName, entityName) {
+ var dotSplit = fieldName.split('.'),
joinEntity = dotSplit.length > 1 ? dotSplit[0] : null,
- fieldName = _.last(dotSplit).split(':')[0],
- entityName = searchEntity;
+ name = _.last(dotSplit).split(':')[0];
// Custom fields contain a dot in their fieldname
// If 3 segments, the first is the joinEntity and the last 2 are the custom field
if (dotSplit.length === 3) {
- fieldName = dotSplit[1] + '.' + fieldName;
+ name = dotSplit[1] + '.' + name;
}
// If 2 segments, it's ambiguous whether this is a custom field or joined field. Search the main entity first.
if (dotSplit.length === 2) {
- var field = _.find(getEntity(true).fields, {name: dotSplit[0] + '.' + fieldName});
+ var field = _.find(getEntity(entityName).fields, {name: dotSplit[0] + '.' + name});
if (field) {
return field;
}
if (joinEntity) {
entityName = _.find(CRM.vars.search.links[entityName], {alias: joinEntity}).entity;
}
- return _.find(getEntity(entityName).fields, {name: fieldName});
+ return _.find(getEntity(entityName).fields, {name: name});
}
return {
getEntity: getEntity,
getField: getField,
parseExpr: function(expr) {
- var result = {},
+ var result = {fn: null, modifier: ''},
fieldName = expr,
bracketPos = expr.indexOf('(');
if (bracketPos >= 0) {
- fieldName = expr.match(/[A-Z( _]*([\w.:]+)/)[1];
+ var parsed = expr.substr(bracketPos).match(/[ ]?([A-Z]+[ ]+)?([\w.:]+)/);
+ fieldName = parsed[2];
result.fn = _.find(CRM.vars.search.functions, {name: expr.substring(0, bracketPos)});
+ result.modifier = _.trim(parsed[1]);
+ }
+ result.field = expr ? getField(fieldName, searchEntity) : undefined;
+ if (result.field) {
+ var split = fieldName.split(':'),
+ prefixPos = split[0].lastIndexOf(result.field.name);
+ result.path = split[0];
+ result.prefix = prefixPos > 0 ? result.path.substring(0, prefixPos) : '';
+ result.suffix = !split[1] ? '' : ':' + split[1];
}
- result.field = getField(fieldName);
- var split = fieldName.split(':'),
- prefixPos = split[0].lastIndexOf(result.field.name);
- result.path = split[0];
- result.prefix = prefixPos > 0 ? result.path.substring(0, prefixPos) : '';
- result.suffix = !split[1] ? '' : ':' + split[1];
return result;
}
};