-#afGuiEditor-main {
+#afGuiEditor {
display: flex;
}
-#afGuiEditor-main .panel.panel-default {
- margin-bottom: 0;
+#afGuiEditor .panel.panel-default {
+ /*margin-bottom: 0;*/
}
-#afGuiEditor-main #afGuiEditor-palette {
+#afGuiEditor #afGuiEditor-palette {
flex: 1;
margin-right: 5px;
}
-#afGuiEditor-main #afGuiEditor-canvas {
+#afGuiEditor #afGuiEditor-canvas {
flex: 1;
margin-left: 5px;
}
-#afGuiEditor-main #afGuiEditor-palette-tabs li > a {
+#afGuiEditor #afGuiEditor-palette-tabs li {
+ top: 1px;
+}
+
+#afGuiEditor #afGuiEditor-palette-tabs li > a {
padding: 10px 15px;
font-size: 12px;
}
-#afGuiEditor-main #afGuiEditor-palette-tabs .dropdown-menu {
+#afGuiEditor #afGuiEditor-palette-tabs .dropdown-menu {
max-height: 500px;
overflow-y: auto;
}
-#afGuiEditor-main #afGuiEditor-palette-config {
+#afGuiEditor .crm-editable-enabled,
+#afGuiEditor-palette-tabs > li > a > span {
+ display: inline-block;
+ padding: 0 4px !important;
+ border: 2px solid transparent !important;
+}
+#afGuiEditor .crm-editable-enabled:hover:not(:focus) {
+ border: 2px dashed grey !important;
+}
+#afGuiEditor .crm-editable-enabled:before,
+#afGuiEditor .crm-editable-enabled:after {
+ content: '';
+ display: none;
+}
+
+#afGuiEditor-palette-config .form-inline {
+ margin-bottom: 10px;
+}
+
+#afGuiEditor-palette-config .form-inline label {
+ min-width: 110px;
}
$scope.afform = null;
$scope.selectedEntity = null;
$scope.meta = CRM.afformAdminData;
+ $scope.controls = {};
var newForm = {
title: ts('Untitled Form'),
layout: {
$scope.selectedEntity = entityName;
};
+ $scope.getField = function(entityName, fieldName) {
+ return _.filter($scope.meta.fields[entityName], {name: fieldName})[0];
+ };
+
+ $scope.valuesFields = function() {
+ var fields = _.transform($scope.meta.fields[$scope.entities[$scope.selectedEntity].type], function(fields, field) {
+ fields.push({id: field.name, text: field.title, disabled: field.name in $scope.entities[$scope.selectedEntity].data});
+ }, []);
+ return {results: fields};
+ };
+
+ $scope.removeValue = function(entity, fieldName) {
+ delete entity.data[fieldName];
+ };
+
+ $scope.$watch('controls.addValue', function(fieldName) {
+ if (fieldName) {
+ $scope.entities[$scope.selectedEntity].data[fieldName] = '';
+ $scope.controls.addValue = '';
+ }
+ });
+
}
};
});
}
// Editable titles using ngModel & html5 contenteditable
+ // Cribbed from ContactLayoutEditor
angular.module('afGuiEditor').directive("afGuiEditable", function() {
return {
restrict: "A",
};
});
+ // Cribbed from the Api4 Explorer
+ angular.module('afGuiEditor').directive('afGuiFieldValue', function() {
+ return {
+ scope: {
+ field: '=afGuiFieldValue'
+ },
+ require: 'ngModel',
+ link: function (scope, element, attrs, ctrl) {
+ var ts = scope.ts = CRM.ts(),
+ multi;
+
+ function destroyWidget() {
+ var $el = $(element);
+ if ($el.is('.crm-form-date-wrapper .crm-hidden-date')) {
+ $el.crmDatepicker('destroy');
+ }
+ if ($el.is('.select2-container + input')) {
+ $el.crmEntityRef('destroy');
+ }
+ $(element).removeData().removeAttr('type').removeAttr('placeholder').show();
+ }
+
+ function makeWidget(field) {
+ var $el = $(element),
+ inputType = field.input_type,
+ dataType = field.data_type;
+ multi = field.serialize || dataType === 'Array';
+ if (inputType === 'Date') {
+ $el.crmDatepicker({time: (field.input_attrs && field.input_attrs.time) || false});
+ }
+ else if (field.fk_entity || field.options || dataType === 'Boolean') {
+ if (field.fk_entity) {
+ $el.crmEntityRef({entity: field.fk_entity, select:{multiple: multi}});
+ } else if (field.options) {
+ var options = _.transform(field.options, function(options, val, key) {
+ options.push({id: key, text: val});
+ }, []);
+ $el.select2({data: options, multiple: multi});
+ } else if (dataType === 'Boolean') {
+ $el.attr('placeholder', ts('- select -')).crmSelect2({allowClear: false, multiple: multi, placeholder: ts('- select -'), data: [
+ {id: '1', text: ts('Yes')},
+ {id: '0', text: ts('No')}
+ ]});
+ }
+ } else if (dataType === 'Integer' && !multi) {
+ $el.attr('type', 'number');
+ }
+ }
+
+ // Copied from ng-list but applied conditionally if field is multi-valued
+ var parseList = function(viewValue) {
+ // If the viewValue is invalid (say required but empty) it will be `undefined`
+ if (_.isUndefined(viewValue)) return;
+
+ if (!multi) {
+ return viewValue;
+ }
+
+ var list = [];
+
+ if (viewValue) {
+ _.each(viewValue.split(','), function(value) {
+ if (value) list.push(_.trim(value));
+ });
+ }
+
+ return list;
+ };
+
+ // Copied from ng-list
+ ctrl.$parsers.push(parseList);
+ ctrl.$formatters.push(function(value) {
+ return _.isArray(value) ? value.join(', ') : value;
+ });
+
+ // Copied from ng-list
+ ctrl.$isEmpty = function(value) {
+ return !value || !value.length;
+ };
+
+ scope.$watchCollection('field', function(field) {
+ destroyWidget();
+ if (field) {
+ makeWidget(field);
+ }
+ });
+ }
+ };
+ });
+
})(angular, CRM.$, CRM._);
<div id="afGuiEditor-palette-config" class="panel panel-default">
<ul id="afGuiEditor-palette-tabs" class="panel-heading nav nav-tabs">
<li role="presentation" ng-class="{active: selectedEntity === null}">
- <a href ng-click="selectEntity(null)">{{ ts('Form Settings') }}</a>
+ <a href ng-click="selectEntity(null)">
+ <span>{{ ts('Form Settings') }}</span>
+ </a>
</li>
<li role="presentation" ng-repeat="entity in entities" ng-class="{active: selectedEntity === entity.name}">
<a href ng-click="selectEntity(entity.name)">
</li>
<li role="presentation" class="dropdown">
<a href class="dropdown-toggle" data-toggle="dropdown">
- <i class="crm-i fa-plus"></i>
+ <span><i class="crm-i fa-plus"></i></span>
</a>
<ul class="dropdown-menu">
<li ng-repeat="entity in meta.entities">
</li>
</ul>
<div class="panel-body" ng-include="'~/afGuiEditor/config-form.html'" ng-if="selectedEntity === null"></div>
- <div class="panel-body" ng-include="'~/afGuiEditor/config-entity.html'" ng-if="selectedEntity !== null"></div>
+ <div class="panel-body" ng-include="'~/afGuiEditor/config-entity.html'" ng-repeat="entity in entities" ng-if="selectedEntity === entity.name"></div>
</div>