Commit | Line | Data |
---|---|---|
b844d2ca CW |
1 | // https://civicrm.org/licensing |
2 | (function(angular, $, _) { | |
3 | "use strict"; | |
4 | ||
5 | angular.module('afGuiEditor').component('afGuiEditor', { | |
6 | templateUrl: '~/afGuiEditor/afGuiEditor.html', | |
7 | bindings: { | |
8 | name: '<' | |
9 | }, | |
10 | controllerAs: 'editor', | |
11 | controller: function($scope, crmApi4, afAdmin, $parse, $timeout, $location) { | |
12 | var ts = $scope.ts = CRM.ts('afform'); | |
13 | $scope.afform = null; | |
14 | $scope.saving = false; | |
15 | $scope.selectedEntityName = null; | |
16 | this.meta = afAdmin.meta; | |
17 | var editor = this; | |
18 | var newForm = { | |
19 | title: '', | |
20 | permission: 'access CiviCRM', | |
21 | layout: [{ | |
22 | '#tag': 'af-form', | |
23 | ctrl: 'afform', | |
24 | '#children': [] | |
25 | }] | |
26 | }; | |
27 | ||
28 | this.$onInit = function() { | |
29 | // Fetch the current form plus all blocks | |
30 | afAdmin.initialize(editor.name) | |
31 | .then(initializeForm); | |
32 | }; | |
33 | ||
34 | // Initialize the current form | |
35 | function initializeForm(afforms) { | |
36 | $scope.afform = _.findWhere(afforms, {name: editor.name}); | |
37 | if (!$scope.afform) { | |
38 | $scope.afform = _.cloneDeep(newForm); | |
39 | if (editor.name != '0') { | |
40 | alert('Error: unknown form "' + editor.name + '"'); | |
41 | } | |
42 | } | |
43 | $scope.canvasTab = 'layout'; | |
44 | $scope.layoutHtml = ''; | |
45 | editor.layout = afAdmin.findRecursive($scope.afform.layout, {'#tag': 'af-form'})[0]; | |
46 | $scope.entities = afAdmin.findRecursive(editor.layout['#children'], {'#tag': 'af-entity'}, 'name'); | |
47 | ||
48 | if (editor.name == '0') { | |
49 | editor.addEntity('Individual'); | |
50 | editor.layout['#children'].push(afAdmin.meta.elements.submit.element); | |
51 | } | |
52 | ||
53 | // Set changesSaved to true on initial load, false thereafter whenever changes are made to the model | |
54 | $scope.changesSaved = editor.name == '0' ? false : 1; | |
55 | $scope.$watch('afform', function () { | |
56 | $scope.changesSaved = $scope.changesSaved === 1; | |
57 | }, true); | |
58 | } | |
59 | ||
60 | $scope.updateLayoutHtml = function() { | |
61 | $scope.layoutHtml = '...Loading...'; | |
62 | crmApi4('Afform', 'convert', {layout: [editor.layout], from: 'deep', to: 'html', formatWhitespace: true}) | |
63 | .then(function(r){ | |
64 | $scope.layoutHtml = r[0].layout || '(Error)'; | |
65 | }) | |
66 | .catch(function(r){ | |
67 | $scope.layoutHtml = '(Error)'; | |
68 | }); | |
69 | }; | |
70 | ||
71 | this.addEntity = function(type) { | |
72 | var meta = afAdmin.meta.entities[type], | |
73 | num = 1; | |
74 | // Give this new entity a unique name | |
75 | while (!!$scope.entities[type + num]) { | |
76 | num++; | |
77 | } | |
78 | $scope.entities[type + num] = _.assign($parse(meta.defaults)($scope), { | |
79 | '#tag': 'af-entity', | |
80 | type: meta.entity, | |
81 | name: type + num, | |
82 | label: meta.label + ' ' + num | |
83 | }); | |
84 | // Add this af-entity tag after the last existing one | |
85 | var pos = 1 + _.findLastIndex(editor.layout['#children'], {'#tag': 'af-entity'}); | |
86 | editor.layout['#children'].splice(pos, 0, $scope.entities[type + num]); | |
87 | // Create a new af-fieldset container for the entity | |
88 | var fieldset = _.cloneDeep(afAdmin.meta.elements.fieldset.element); | |
89 | fieldset['af-fieldset'] = type + num; | |
90 | fieldset['#children'][0]['#children'][0]['#text'] = meta.label + ' ' + num; | |
91 | // Add default contact name block | |
92 | if (meta.entity === 'Contact') { | |
93 | fieldset['#children'].push({'#tag': 'afblock-name-' + type.toLowerCase()}); | |
94 | } | |
95 | // Attempt to place the new af-fieldset after the last one on the form | |
96 | pos = 1 + _.findLastIndex(editor.layout['#children'], 'af-fieldset'); | |
97 | if (pos) { | |
98 | editor.layout['#children'].splice(pos, 0, fieldset); | |
99 | } else { | |
100 | editor.layout['#children'].push(fieldset); | |
101 | } | |
102 | return type + num; | |
103 | }; | |
104 | ||
105 | this.removeEntity = function(entityName) { | |
106 | delete $scope.entities[entityName]; | |
107 | afAdmin.removeRecursive(editor.layout['#children'], {'#tag': 'af-entity', name: entityName}); | |
108 | afAdmin.removeRecursive(editor.layout['#children'], {'af-fieldset': entityName}); | |
109 | this.selectEntity(null); | |
110 | }; | |
111 | ||
112 | this.selectEntity = function(entityName) { | |
113 | $scope.selectedEntityName = entityName; | |
114 | }; | |
115 | ||
116 | this.getEntity = function(entityName) { | |
117 | return $scope.entities[entityName]; | |
118 | }; | |
119 | ||
120 | this.getSelectedEntityName = function() { | |
121 | return $scope.selectedEntityName; | |
122 | }; | |
123 | ||
124 | // Validates that a drag-n-drop action is allowed | |
125 | this.onDrop = function(event, ui) { | |
126 | var sort = ui.item.sortable; | |
127 | // Check if this is a callback for an item dropped into a different container | |
128 | // @see https://github.com/angular-ui/ui-sortable notes on canceling | |
129 | if (!sort.received && sort.source[0] !== sort.droptarget[0]) { | |
130 | var $source = $(sort.source[0]), | |
131 | $target = $(sort.droptarget[0]), | |
132 | $item = $(ui.item[0]); | |
133 | // Fields cannot be dropped outside their own entity | |
134 | if ($item.is('[af-gui-field]') || $item.has('[af-gui-field]').length) { | |
135 | if ($source.closest('[data-entity]').attr('data-entity') !== $target.closest('[data-entity]').attr('data-entity')) { | |
136 | return sort.cancel(); | |
137 | } | |
138 | } | |
139 | // Entity-fieldsets cannot be dropped into other entity-fieldsets | |
140 | if ((sort.model['af-fieldset'] || $item.has('.af-gui-fieldset').length) && $target.closest('.af-gui-fieldset').length) { | |
141 | return sort.cancel(); | |
142 | } | |
143 | } | |
144 | }; | |
145 | ||
146 | $scope.addEntity = function(entityType) { | |
147 | var entityName = editor.addEntity(entityType); | |
148 | editor.selectEntity(entityName); | |
149 | }; | |
150 | ||
151 | $scope.save = function() { | |
152 | $scope.saving = $scope.changesSaved = true; | |
153 | crmApi4('Afform', 'save', {formatWhitespace: true, records: [JSON.parse(angular.toJson($scope.afform))]}) | |
154 | .then(function (data) { | |
155 | $scope.saving = false; | |
156 | $scope.afform.name = data[0].name; | |
157 | // FIXME: This causes an unnecessary reload when saving a new form | |
158 | $location.search('name', data[0].name); | |
159 | }); | |
160 | }; | |
161 | ||
162 | $scope.$watch('afform.title', function(newTitle, oldTitle) { | |
163 | if (typeof oldTitle === 'string') { | |
164 | _.each($scope.entities, function(entity) { | |
165 | if (entity.data && entity.data.source === oldTitle) { | |
166 | entity.data.source = newTitle; | |
167 | } | |
168 | }); | |
169 | } | |
170 | }); | |
171 | } | |
172 | }); | |
173 | ||
174 | })(angular, CRM.$, CRM._); |