Afform GUI - Rename service from afAdmin to afGiu
[civicrm-core.git] / ext / afform / admin / ang / afGuiEditor / elements / afGuiContainer.component.js
CommitLineData
ab3c1d83
CW
1// https://civicrm.org/licensing
2(function(angular, $, _) {
3 "use strict";
4
5 angular.module('afGuiEditor').component('afGuiContainer', {
6 templateUrl: '~/afGuiEditor/elements/afGuiContainer.html',
7 bindings: {
8 node: '<',
9 join: '<',
10 entityName: '<',
11 deleteThis: '&'
12 },
13 require: {editor: '^^afGuiEditor'},
23fd8685 14 controller: function($scope, crmApi4, dialogService, afGui) {
ab3c1d83
CW
15 var ts = $scope.ts = CRM.ts(),
16 ctrl = this;
17
18 this.$onInit = function() {
23fd8685 19 if ((ctrl.node['#tag'] in afGui.meta.blocks) || ctrl.join) {
ab3c1d83
CW
20 initializeBlockContainer();
21 }
22 };
23
24 $scope.isSelectedFieldset = function(entityName) {
25 return entityName === ctrl.editor.getSelectedEntityName();
26 };
27
28 $scope.selectEntity = function() {
29 if (ctrl.node['af-fieldset']) {
30 ctrl.editor.selectEntity(ctrl.node['af-fieldset']);
31 }
32 };
33
34 $scope.tags = {
35 div: ts('Container'),
36 fieldset: ts('Fieldset')
37 };
38
39 // Block settings
40 var block = {};
41 $scope.block = null;
42
43 $scope.getSetChildren = function(val) {
44 var collection = block.layout || (ctrl.node && ctrl.node['#children']);
45 return arguments.length ? (collection = val) : collection;
46 };
47
48 $scope.isRepeatable = function() {
23fd8685 49 return ctrl.node['af-fieldset'] || (block.directive && afGui.meta.blocks[block.directive].repeat) || ctrl.join;
ab3c1d83
CW
50 };
51
52 $scope.toggleRepeat = function() {
53 if ('af-repeat' in ctrl.node) {
54 delete ctrl.node.max;
55 delete ctrl.node.min;
56 delete ctrl.node['af-repeat'];
57 delete ctrl.node['add-icon'];
58 } else {
59 ctrl.node.min = '1';
60 ctrl.node['af-repeat'] = ts('Add');
61 }
62 };
63
64 $scope.getSetMin = function(val) {
65 if (arguments.length) {
66 if (ctrl.node.max && val > parseInt(ctrl.node.max, 10)) {
67 ctrl.node.max = '' + val;
68 }
69 if (!val) {
70 delete ctrl.node.min;
71 }
72 else {
73 ctrl.node.min = '' + val;
74 }
75 }
76 return ctrl.node.min ? parseInt(ctrl.node.min, 10) : null;
77 };
78
79 $scope.getSetMax = function(val) {
80 if (arguments.length) {
81 if (ctrl.node.min && val && val < parseInt(ctrl.node.min, 10)) {
82 ctrl.node.min = '' + val;
83 }
84 if (typeof val !== 'number') {
85 delete ctrl.node.max;
86 }
87 else {
88 ctrl.node.max = '' + val;
89 }
90 }
91 return ctrl.node.max ? parseInt(ctrl.node.max, 10) : null;
92 };
93
94 $scope.pickAddIcon = function() {
23fd8685 95 afGui.pickIcon().then(function(val) {
ab3c1d83
CW
96 ctrl.node['add-icon'] = val;
97 });
98 };
99
100 function getBlockNode() {
101 return !ctrl.join ? ctrl.node : (ctrl.node['#children'] && ctrl.node['#children'].length === 1 ? ctrl.node['#children'][0] : null);
102 }
103
104 function setBlockDirective(directive) {
105 if (ctrl.join) {
106 ctrl.node['#children'] = [{'#tag': directive}];
107 } else {
108 delete ctrl.node['#children'];
109 delete ctrl.node['class'];
110 ctrl.node['#tag'] = directive;
111 }
112 }
113
114 function overrideBlockContents(layout) {
115 ctrl.node['#children'] = layout || [];
116 if (!ctrl.join) {
117 ctrl.node['#tag'] = 'div';
118 ctrl.node['class'] = 'af-container';
119 }
120 block.layout = block.directive = null;
121 }
122
123 $scope.layouts = {
124 'af-layout-rows': ts('Contents display as rows'),
125 'af-layout-cols': ts('Contents are evenly-spaced columns'),
126 'af-layout-inline': ts('Contents are arranged inline')
127 };
128
129 $scope.getLayout = function() {
130 if (!ctrl.node) {
131 return '';
132 }
23fd8685 133 return _.intersection(afGui.splitClass(ctrl.node['class']), _.keys($scope.layouts))[0] || 'af-layout-rows';
ab3c1d83
CW
134 };
135
136 $scope.setLayout = function(val) {
137 var classes = ['af-container'];
138 if (val !== 'af-layout-rows') {
139 classes.push(val);
140 }
23fd8685 141 afGui.modifyClasses(ctrl.node, _.keys($scope.layouts), classes);
ab3c1d83
CW
142 };
143
144 $scope.selectBlockDirective = function() {
145 if (block.directive) {
23fd8685 146 block.layout = _.cloneDeep(afGui.meta.blocks[block.directive].layout);
ab3c1d83
CW
147 block.original = block.directive;
148 setBlockDirective(block.directive);
149 }
150 else {
151 overrideBlockContents(block.layout);
152 }
153 };
154
155 function initializeBlockContainer() {
156
157 // Cancel the below $watch expressions if already set
158 _.each(block.listeners, function(deregister) {
159 deregister();
160 });
161
162 block = $scope.block = {
163 directive: null,
164 layout: null,
165 original: null,
166 options: [],
167 listeners: []
168 };
169
23fd8685 170 _.each(afGui.meta.blocks, function(blockInfo, directive) {
ab3c1d83
CW
171 if (directive === ctrl.node['#tag'] || blockInfo.join === ctrl.getFieldEntityType()) {
172 block.options.push({
173 id: directive,
174 text: blockInfo.title
175 });
176 }
177 });
178
23fd8685 179 if (getBlockNode() && getBlockNode()['#tag'] in afGui.meta.blocks) {
ab3c1d83 180 block.directive = block.original = getBlockNode()['#tag'];
23fd8685 181 block.layout = _.cloneDeep(afGui.meta.blocks[block.directive].layout);
ab3c1d83
CW
182 }
183
184 block.listeners.push($scope.$watch('block.layout', function (layout, oldVal) {
23fd8685 185 if (block.directive && layout && layout !== oldVal && !angular.equals(layout, afGui.meta.blocks[block.directive].layout)) {
ab3c1d83
CW
186 overrideBlockContents(block.layout);
187 }
188 }, true));
189 }
190
191 $scope.saveBlock = function() {
192 var options = CRM.utils.adjustDialogDefaults({
193 width: '500px',
194 height: '300px',
195 autoOpen: false,
196 title: ts('Save block')
197 });
198 var model = {
199 title: '',
200 name: null,
201 layout: ctrl.node['#children']
202 };
203 if (ctrl.join) {
204 model.join = ctrl.join;
205 }
206 if ($scope.block && $scope.block.original) {
23fd8685
CW
207 model.title = afGui.meta.blocks[$scope.block.original].title;
208 model.name = afGui.meta.blocks[$scope.block.original].name;
209 model.block = afGui.meta.blocks[$scope.block.original].block;
ab3c1d83
CW
210 }
211 else {
212 model.block = ctrl.container.getFieldEntityType() || '*';
213 }
214 dialogService.open('saveBlockDialog', '~/afGuiEditor/saveBlock.html', model, options)
215 .then(function(block) {
23fd8685 216 afGui.meta.blocks[block.directive_name] = block;
ab3c1d83
CW
217 setBlockDirective(block.directive_name);
218 initializeBlockContainer();
219 });
220 };
221
222 this.node = ctrl.node;
223
224 this.getNodeType = function(node) {
225 if (!node) {
226 return null;
227 }
228 if (node['#tag'] === 'af-field') {
229 return 'field';
230 }
231 if (node['af-fieldset']) {
232 return 'fieldset';
233 }
234 if (node['af-join']) {
235 return 'join';
236 }
23fd8685 237 if (node['#tag'] && node['#tag'] in afGui.meta.blocks) {
ab3c1d83
CW
238 return 'container';
239 }
23fd8685 240 var classes = afGui.splitClass(node['class']),
ab3c1d83
CW
241 types = ['af-container', 'af-text', 'af-button', 'af-markup'],
242 type = _.intersection(types, classes);
243 return type.length ? type[0].replace('af-', '') : null;
244 };
245
246 this.removeElement = function(element) {
23fd8685 247 afGui.removeRecursive($scope.getSetChildren(), {$$hashKey: element.$$hashKey});
ab3c1d83
CW
248 };
249
250 this.getEntityName = function() {
251 return ctrl.entityName.split('-join-')[0];
252 };
253
254 // Returns the primary entity type for this container e.g. "Contact"
255 this.getMainEntityType = function() {
256 return ctrl.editor && ctrl.editor.getEntity(ctrl.getEntityName()).type;
257 };
258
259 // Returns the entity type for fields within this conainer (join entity type if this is a join, else the primary entity type)
260 this.getFieldEntityType = function() {
261 var joinType = ctrl.entityName.split('-join-');
262 return joinType[1] || (ctrl.editor && ctrl.editor.getEntity(joinType[0]).type);
263 };
264
265 }
266 });
267
268})(angular, CRM.$, CRM._);