6a1bc9a50f9d28f3cde17bfb696001d7c50a839b
[civicrm-core.git] / js / angular-crmCaseType.js
1 (function(angular, $, _) {
2
3 var partialUrl = function(relPath) {
4 return CRM.resourceUrls['civicrm'] + '/partials/crmCaseType/' + relPath;
5 };
6
7 var crmCaseType = angular.module('crmCaseType', ['ngRoute', 'ui.utils', 'crmUi', 'unsavedChanges']);
8
9 var newCaseTypeDefinitionTemplate = {
10 activityTypes: [
11 {name: 'Open Case', max_instances: 1 }
12 ],
13 activitySets: [
14 {
15 name: 'standard_timeline',
16 label: 'Standard Timeline',
17 timeline: '1', // Angular won't bind checkbox correctly with numeric 1
18 activityTypes: [
19 {name: 'Open Case', status: 'Completed' }
20 ]
21 }
22 ],
23 caseRoles: [
24 { name: 'Case Coordinator', creator: '1', manager: '1'}
25 ]
26 };
27
28 crmCaseType.config(['$routeProvider',
29 function($routeProvider) {
30 $routeProvider.when('/caseType', {
31 templateUrl: partialUrl('list.html'),
32 controller: 'CaseTypeListCtrl',
33 resolve: {
34 caseTypes: function($route, crmApi) {
35 return crmApi('CaseType', 'get', {});
36 }
37 }
38 });
39 $routeProvider.when('/caseType/:id', {
40 templateUrl: partialUrl('edit.html'),
41 controller: 'CaseTypeCtrl',
42 resolve: {
43 selectedCaseType: function($route, crmApi) {
44 if ( $route.current.params.id !== 'new') {
45 return crmApi('CaseType', 'getsingle', {id: $route.current.params.id});
46 }
47 else {
48 return { title: "", name: "", is_active: "1", weight: "1",
49 definition: _.extend({}, newCaseTypeDefinitionTemplate) };
50 }
51 }
52 }
53 });
54 }
55 ]);
56
57 // Add a new record by name.
58 // Ex: <crmAddName crm-options="['Alpha','Beta','Gamma']" crm-var="newItem" crm-on-add="callMyCreateFunction(newItem)" />
59 crmCaseType.directive('crmAddName', function() {
60 return {
61 restrict: 'AE',
62 template: '<input class="add-activity" type="hidden" />',
63 link: function(scope, element, attrs) {
64 /// Format list of options for select2's "data"
65 var getFormattedOptions = function() {
66 return {
67 results: _.map(scope[attrs.crmOptions], function(option){
68 return {id: option, text: option};
69 })
70 };
71 };
72
73 var input = $('input', element);
74
75 scope._resetSelection = function() {
76 $(input).select2('close');
77 $(input).select2('val', '');
78 scope[attrs.crmVar] = '';
79 };
80
81 $(input).select2({
82 data: getFormattedOptions,
83 createSearchChoice: function(term) {
84 return {id: term, text: term};
85 }
86 });
87 $(input).on('select2-selecting', function(e) {
88 scope[attrs.crmVar] = e.val;
89 scope.$evalAsync(attrs.crmOnAdd);
90 scope.$evalAsync('_resetSelection()');
91 e.preventDefault();
92 });
93
94 scope.$watch(attrs.crmOptions, function(value) {
95 $(input).select2('data', getFormattedOptions);
96 $(input).select2('val', '');
97 });
98 }
99 };
100 });
101
102 crmCaseType.controller('CaseTypeCtrl', function($scope, crmApi, selectedCaseType) {
103 $scope.partialUrl = partialUrl;
104
105 $scope.activityStatuses = CRM.crmCaseType.actStatuses;
106 $scope.activityTypes = CRM.crmCaseType.actTypes;
107 $scope.activityTypeNames = _.pluck(CRM.crmCaseType.actTypes, 'name');
108 $scope.relationshipTypeNames = _.pluck(CRM.crmCaseType.relTypes, 'label_b_a'); // label_b_a is CRM_Case_XMLProcessor::REL_TYPE_CNAME
109 $scope.locks = {caseTypeName: true};
110
111 $scope.workflows = {
112 'timeline': 'Timeline',
113 'sequence': 'Sequence'
114 };
115
116 $scope.caseType = selectedCaseType;
117 $scope.caseType.definition = $scope.caseType.definition || [];
118 $scope.caseType.definition.activityTypes = $scope.caseType.definition.activityTypes || [];
119 $scope.caseType.definition.activitySets = $scope.caseType.definition.activitySets || [];
120 $scope.caseType.definition.caseRoles = $scope.caseType.definition.caseRoles || [];
121 window.ct = $scope.caseType;
122
123 $scope.addActivitySet = function(workflow) {
124 var activitySet = {};
125 activitySet[workflow] = '1';
126 activitySet.activityTypes = [];
127
128 var offset = 1;
129 var names = _.pluck($scope.caseType.definition.activitySets, 'name');
130 while (_.contains(names, workflow + '_' + offset)) offset++;
131 activitySet.name = workflow + '_' + offset;
132 activitySet.label = (offset == 1 ) ? $scope.workflows[workflow] : ($scope.workflows[workflow] + ' #' + offset);
133
134 $scope.caseType.definition.activitySets.push(activitySet);
135 _.defer(function() {
136 $('.crmCaseType-acttab').tabs('refresh').tabs({active: -1});
137 });
138 };
139
140 /// Add a new activity entry to an activity-set
141 $scope.addActivity = function(activitySet, activityType) {
142 activitySet.activityTypes.push({
143 name: activityType,
144 status: 'Scheduled',
145 reference_activity: 'Open Case',
146 reference_offset: '1',
147 reference_select: 'newest'
148 });
149 if (!_.contains($scope.activityTypeNames, activityType)) {
150 $scope.activityTypeNames.push(activityType);
151 }
152 };
153
154 /// Add a new top-level activity-type entry
155 $scope.addActivityType = function(activityType) {
156 var names = _.pluck($scope.caseType.definition.activityTypes, 'name');
157 if (!_.contains(names, activityType)) {
158 $scope.caseType.definition.activityTypes.push({
159 name: activityType
160 });
161
162 }
163 if (!_.contains($scope.activityTypeNames, activityType)) {
164 $scope.activityTypeNames.push(activityType);
165 }
166 };
167
168 /// Add a new role
169 $scope.addRole = function(roles, roleName) {
170 var names = _.pluck($scope.caseType.definition.caseRoles, 'name');
171 if (!_.contains(names, roleName)) {
172 roles.push({
173 name: roleName
174 });
175 }
176 if (!_.contains($scope.relationshipTypeNames, roleName)) {
177 $scope.relationshipTypeNames.push(roleName);
178 }
179 };
180
181 $scope.onManagerChange = function(managerRole) {
182 angular.forEach($scope.caseType.definition.caseRoles, function(caseRole) {
183 if (caseRole != managerRole) {
184 caseRole.manager = '0';
185 }
186 });
187 };
188
189 $scope.removeItem = function(array, item) {
190 var idx = _.indexOf(array, item);
191 if (idx != -1) {
192 array.splice(idx, 1);
193 }
194 };
195
196 $scope.isNewActivitySetAllowed = function(workflow) {
197 switch (workflow) {
198 case 'timeline':
199 return true;
200 case 'sequence':
201 return 0 == _.where($scope.caseType.definition.activitySets, {sequence: '1'}).length;
202 default:
203 if (console && console.log) console.log('Denied access to unrecognized workflow: (' + workflow + ')');
204 return false;
205 }
206 };
207
208 $scope.getWorkflowName = function(activitySet) {
209 var result = 'Unknown';
210 _.each($scope.workflows, function(value, key) {
211 if (activitySet[key]) result = value;
212 });
213 return result;
214 };
215
216 /**
217 * Determine which HTML partial to use for a particular
218 *
219 * @return string URL of the HTML partial
220 */
221 $scope.activityTableTemplate = function(activitySet) {
222 if (activitySet.timeline) {
223 return partialUrl('timelineTable.html');
224 } else if (activitySet.sequence) {
225 return partialUrl('sequenceTable.html');
226 } else {
227 return '';
228 }
229 };
230
231 $scope.dump = function() {
232 console.log($scope.caseType);
233 };
234
235 $scope.save = function() {
236 var result = crmApi('CaseType', 'create', $scope.caseType, true);
237 result.success(function(data) {
238 if (data.is_error == 0) {
239 $scope.caseType.id = data.id;
240 window.location.href = '#/caseType';
241 }
242 });
243 };
244
245 $scope.$watchCollection('caseType.definition.activitySets', function() {
246 _.defer(function() {
247 $('.crmCaseType-acttab').tabs('refresh');
248 });
249 });
250
251 var updateCaseTypeName = function () {
252 if (!$scope.caseType.id && $scope.locks.caseTypeName) {
253 // Should we do some filtering? Lowercase? Strip whitespace?
254 var t = $scope.caseType.title ? $scope.caseType.title : '';
255 $scope.caseType.name = t.replace(/ /g, '_').replace(/[^a-zA-Z0-9_]/g, '').toLowerCase();
256 }
257 };
258 $scope.$watch('locks.caseTypeName', updateCaseTypeName);
259 $scope.$watch('caseType.title', updateCaseTypeName);
260 });
261
262 crmCaseType.controller('CaseTypeListCtrl', function($scope, crmApi, caseTypes) {
263 $scope.caseTypes = caseTypes.values;
264 });
265
266 })(angular, CRM.$, CRM._);