4cbe9a44f2a3999300d8591ae5b99fa1f5bc1cb9
1 // https://civicrm.org/licensing
2 (function(angular
, $, _
) {
5 angular
.module('afGuiEditor').component('afGuiEditor', {
6 templateUrl
: '~/afGuiEditor/afGuiEditor.html',
12 controllerAs
: 'editor',
13 controller: function($scope
, crmApi4
, afGui
, $parse
, $timeout
, $location
) {
14 var ts
= $scope
.ts
= CRM
.ts('afform');
16 $scope
.saving
= false;
17 $scope
.selectedEntityName
= null;
18 this.meta
= afGui
.meta
;
21 this.$onInit = function() {
22 // Load the current form plus blocks & fields
24 afGui
.addMeta(this.data
);
28 // Initialize the current form
29 function initializeForm() {
30 $scope
.afform
= editor
.data
.definition
;
32 alert('Error: unknown form');
34 if (editor
.mode
=== 'clone') {
35 delete $scope
.afform
.name
;
36 $scope
.afform
.title
+= ' ' + ts('(copy)');
38 $scope
.canvasTab
= 'layout';
39 $scope
.layoutHtml
= '';
40 editor
.layout
= {'#children': []};
43 if ($scope
.afform
.type
=== 'form') {
44 editor
.allowEntityConfig
= true;
45 editor
.layout
['#children'] = afGui
.findRecursive($scope
.afform
.layout
, {'#tag': 'af-form'})[0]['#children'];
46 $scope
.entities
= afGui
.findRecursive(editor
.layout
['#children'], {'#tag': 'af-entity'}, 'name');
48 if (editor
.mode
=== 'create') {
49 editor
.addEntity(editor
.entity
);
50 editor
.layout
['#children'].push(afGui
.meta
.elements
.submit
.element
);
54 if ($scope
.afform
.type
=== 'block') {
55 editor
.layout
['#children'] = $scope
.afform
.layout
;
56 editor
.blockEntity
= $scope
.afform
.join
|| $scope
.afform
.block
;
57 $scope
.entities
[editor
.blockEntity
] = {
58 type
: editor
.blockEntity
,
59 name
: editor
.blockEntity
,
60 label
: afGui
.getEntity(editor
.blockEntity
).label
64 if ($scope
.afform
.type
=== 'search') {
65 editor
.layout
['#children'] = afGui
.findRecursive($scope
.afform
.layout
, {'af-fieldset': ''})[0]['#children'];
69 // Set changesSaved to true on initial load, false thereafter whenever changes are made to the model
70 $scope
.changesSaved
= editor
.mode
=== 'edit' ? 1 : false;
71 $scope
.$watch('afform', function () {
72 $scope
.changesSaved
= $scope
.changesSaved
=== 1;
76 $scope
.updateLayoutHtml = function() {
77 $scope
.layoutHtml
= '...Loading...';
78 crmApi4('Afform', 'convert', {layout
: [editor
.layout
], from: 'deep', to
: 'html', formatWhitespace
: true})
80 $scope
.layoutHtml
= r
[0].layout
|| '(Error)';
83 $scope
.layoutHtml
= '(Error)';
87 this.addEntity = function(type
, selectTab
) {
88 var meta
= afGui
.meta
.entities
[type
],
90 // Give this new entity a unique name
91 while (!!$scope
.entities
[type
+ num
]) {
94 $scope
.entities
[type
+ num
] = _
.assign($parse(meta
.defaults
)($scope
), {
98 label
: meta
.label
+ ' ' + num
,
102 function addToCanvas() {
103 // Add this af-entity tag after the last existing one
104 var pos
= 1 + _
.findLastIndex(editor
.layout
['#children'], {'#tag': 'af-entity'});
105 editor
.layout
['#children'].splice(pos
, 0, $scope
.entities
[type
+ num
]);
106 // Create a new af-fieldset container for the entity
107 var fieldset
= _
.cloneDeep(afGui
.meta
.elements
.fieldset
.element
);
108 fieldset
['af-fieldset'] = type
+ num
;
109 fieldset
['#children'][0]['#children'][0]['#text'] = meta
.label
+ ' ' + num
;
110 // Add boilerplate contents
111 _
.each(meta
.boilerplate
, function (tag
) {
112 fieldset
['#children'].push(tag
);
114 // Attempt to place the new af-fieldset after the last one on the form
115 pos
= 1 + _
.findLastIndex(editor
.layout
['#children'], 'af-fieldset');
117 editor
.layout
['#children'].splice(pos
, 0, fieldset
);
119 editor
.layout
['#children'].push(fieldset
);
121 delete $scope
.entities
[type
+ num
].loading
;
123 editor
.selectEntity(type
+ num
);
130 crmApi4('Afform', 'loadAdminData', {
131 definition
: {type
: 'form'},
133 }, 0).then(function(data
) {
140 this.removeEntity = function(entityName
) {
141 delete $scope
.entities
[entityName
];
142 afGui
.removeRecursive(editor
.layout
['#children'], {'#tag': 'af-entity', name
: entityName
});
143 afGui
.removeRecursive(editor
.layout
['#children'], {'af-fieldset': entityName
});
144 this.selectEntity(null);
147 this.selectEntity = function(entityName
) {
148 $scope
.selectedEntityName
= entityName
;
151 this.getEntity = function(entityName
) {
152 return $scope
.entities
[entityName
];
155 this.getSelectedEntityName = function() {
156 return $scope
.selectedEntityName
;
159 // Validates that a drag-n-drop action is allowed
160 this.onDrop = function(event
, ui
) {
161 var sort
= ui
.item
.sortable
;
162 // Check if this is a callback for an item dropped into a different container
163 // @see https://github.com/angular-ui/ui-sortable notes on canceling
164 if (!sort
.received
&& sort
.source
[0] !== sort
.droptarget
[0]) {
165 var $source
= $(sort
.source
[0]),
166 $target
= $(sort
.droptarget
[0]),
167 $item
= $(ui
.item
[0]);
168 // Fields cannot be dropped outside their own entity
169 if ($item
.is('[af-gui-field]') || $item
.has('[af-gui-field]').length
) {
170 if ($source
.closest('[data-entity]').attr('data-entity') !== $target
.closest('[data-entity]').attr('data-entity')) {
171 return sort
.cancel();
174 // Entity-fieldsets cannot be dropped into other entity-fieldsets
175 if ((sort
.model
['af-fieldset'] || $item
.has('.af-gui-fieldset').length
) && $target
.closest('.af-gui-fieldset').length
) {
176 return sort
.cancel();
181 $scope
.save = function() {
182 $scope
.saving
= $scope
.changesSaved
= true;
183 crmApi4('Afform', 'save', {formatWhitespace
: true, records
: [JSON
.parse(angular
.toJson($scope
.afform
))]})
184 .then(function (data
) {
185 $scope
.saving
= false;
186 $scope
.afform
.name
= data
[0].name
;
187 if (editor
.mode
!== 'edit') {
188 $location
.url('/edit/' + data
[0].name
);
193 $scope
.$watch('afform.title', function(newTitle
, oldTitle
) {
194 if (typeof oldTitle
=== 'string') {
195 _
.each($scope
.entities
, function(entity
) {
196 if (entity
.data
&& entity
.data
.source
=== oldTitle
) {
197 entity
.data
.source
= newTitle
;
205 })(angular
, CRM
.$, CRM
._
);