1 (function(angular
, $, _
) {
3 angular
.module('afGuiEditor', CRM
.angRequires('afGuiEditor'))
5 .service('afAdmin', function(crmApi4
, $parse
, $q
) {
7 // Parse strings of javascript that php couldn't interpret
8 function evaluate(collection
) {
9 _
.each(collection
, function(item
) {
10 if (_
.isPlainObject(item
)) {
11 evaluate(item
['#children']);
12 _
.each(item
, function(node
, idx
) {
13 if (_
.isString(node
)) {
14 var str
= _
.trim(node
);
15 if (str
[0] === '{' || str
[0] === '[' || str
.slice(0, 3) === 'ts(') {
16 item
[idx
] = $parse(str
)({ts
: CRM
.ts('afform')});
24 function getStyles(node
) {
25 return !node
|| !node
.style
? {} : _
.transform(node
.style
.split(';'), function(styles
, style
) {
26 var keyVal
= _
.map(style
.split(':'), _
.trim
);
27 if (keyVal
.length
> 1 && keyVal
[1].length
) {
28 styles
[keyVal
[0]] = keyVal
[1];
33 function setStyle(node
, name
, val
) {
34 var styles
= getStyles(node
);
39 if (_
.isEmpty(styles
)) {
42 node
.style
= _
.transform(styles
, function(combined
, val
, name
) {
43 combined
.push(name
+ ': ' + val
);
48 // Turns a space-separated list (e.g. css classes) into an array
49 function splitClass(str
) {
53 return str
? _
.unique(_
.trim(str
).split(/\s+/g)) : [];
56 function modifyClasses(node
, toRemove
, toAdd
) {
57 var classes
= splitClass(node
['class']);
59 classes
= _
.difference(classes
, splitClass(toRemove
));
62 classes
= _
.unique(classes
.concat(splitClass(toAdd
)));
64 node
['class'] = classes
.join(' ');
68 // Initialize/refresh data about the current afform + available blocks
69 initialize: function(afName
) {
70 var promise
= crmApi4('Afform', 'get', {
71 layoutFormat
: 'shallow',
72 formatWhitespace
: true,
73 where
: [afName
? ["OR", [["name", "=", afName
], ["block", "IS NOT NULL"]]] : ["block", "IS NOT NULL"]]
75 promise
.then(function(afforms
) {
76 CRM
.afGuiEditor
.blocks
= {};
77 _
.each(afforms
, function(form
) {
78 evaluate(form
.layout
);
80 CRM
.afGuiEditor
.blocks
[form
.directive_name
] = form
;
87 meta
: CRM
.afGuiEditor
,
89 getField: function(entityType
, fieldName
) {
90 return CRM
.afGuiEditor
.entities
[entityType
].fields
[fieldName
];
93 // Recursively searches a collection and its children using _.filter
94 // Returns an array of all matches, or an object if the indexBy param is used
95 findRecursive
: function findRecursive(collection
, predicate
, indexBy
) {
96 var items
= _
.filter(collection
, predicate
);
97 _
.each(collection
, function(item
) {
98 if (_
.isPlainObject(item
) && item
['#children']) {
99 var childMatches
= findRecursive(item
['#children'], predicate
);
100 if (childMatches
.length
) {
101 Array
.prototype.push
.apply(items
, childMatches
);
105 return indexBy
? _
.indexBy(items
, indexBy
) : items
;
108 // Applies _.remove() to an item and its children
109 removeRecursive
: function removeRecursive(collection
, removeParams
) {
110 _
.remove(collection
, removeParams
);
111 _
.each(collection
, function(item
) {
112 if (_
.isPlainObject(item
) && item
['#children']) {
113 removeRecursive(item
['#children'], removeParams
);
118 splitClass
: splitClass
,
119 modifyClasses
: modifyClasses
,
120 getStyles
: getStyles
,
123 pickIcon: function() {
124 var deferred
= $q
.defer();
125 $('#af-gui-icon-picker').off('change').siblings('.crm-icon-picker-button').click();
126 $('#af-gui-icon-picker').on('change', function() {
127 deferred
.resolve($(this).val());
129 return deferred
.promise
;
134 // Shoehorn in a non-angular widget for picking icons
136 $('#crm-container').append('<div style="display:none"><input id="af-gui-icon-picker"></div>');
137 CRM
.loadScript(CRM
.config
.resourceBase
+ 'js/jquery/jquery.crmIconPicker.js').done(function() {
138 $('#af-gui-icon-picker').crmIconPicker();
142 // Connect bootstrap dropdown.js with angular
143 // Allows menu content to be conditionally rendered only if open
144 // This gives a large performance boost for a page with lots of menus
145 angular
.module('afGuiEditor').directive('afGuiMenu', function() {
148 link: function($scope
, element
, attrs
) {
151 .on('show.bs.dropdown', function() {
152 $scope
.$apply(function() {
153 $scope
.menu
.open
= true;
156 .on('hidden.bs.dropdown', function() {
157 $scope
.$apply(function() {
158 $scope
.menu
.open
= false;
165 })(angular
, CRM
.$, CRM
._
);