From 64f8f6cd8cbc45bfb51915db8daea3e2e509b29c Mon Sep 17 00:00:00 2001 From: Coleman Watts Date: Mon, 31 Oct 2022 07:54:33 -0400 Subject: [PATCH] Afform - Support editing new element types added by extensions This allows extensions (e.g. ReCaptcha) to provide new element types. They are editable in the GUI via a generic template, and exensions can provide their own templates for further configurability. --- ext/afform/admin/ang/afGuiEditor.css | 1 + .../elements/afGuiContainer.component.js | 9 +++++ .../afGuiEditor/elements/afGuiContainer.html | 1 + .../elements/afGuiGenericElement-menu.html | 1 + .../elements/afGuiGenericElement.html | 14 ++++++++ .../elements/afGuiGenericElement.js | 33 +++++++++++++++++++ ext/afform/core/ang/af/afForm.component.js | 2 +- 7 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 ext/afform/admin/ang/afGuiEditor/elements/afGuiGenericElement-menu.html create mode 100644 ext/afform/admin/ang/afGuiEditor/elements/afGuiGenericElement.html create mode 100644 ext/afform/admin/ang/afGuiEditor/elements/afGuiGenericElement.js diff --git a/ext/afform/admin/ang/afGuiEditor.css b/ext/afform/admin/ang/afGuiEditor.css index 75fff3e3d393..3aca35836f65 100644 --- a/ext/afform/admin/ang/afGuiEditor.css +++ b/ext/afform/admin/ang/afGuiEditor.css @@ -194,6 +194,7 @@ body.af-gui-dragging { position: relative; padding: 0 3px 3px; display: block; + min-height: 21px; } #afGuiEditor .af-gui-container { diff --git a/ext/afform/admin/ang/afGuiEditor/elements/afGuiContainer.component.js b/ext/afform/admin/ang/afGuiEditor/elements/afGuiContainer.component.js index a61c47e1447f..06c8648d1a13 100644 --- a/ext/afform/admin/ang/afGuiEditor/elements/afGuiContainer.component.js +++ b/ext/afform/admin/ang/afGuiEditor/elements/afGuiContainer.component.js @@ -17,6 +17,7 @@ controller: function($scope, $element, crmApi4, dialogService, afGui) { var ts = $scope.ts = CRM.ts('org.civicrm.afform_admin'), ctrl = this; + var genericElements = []; this.$onInit = function() { if (ctrl.node['#tag'] && ((ctrl.node['#tag'] in afGui.meta.blocks) || ctrl.join)) { @@ -39,6 +40,11 @@ } initializeBlockContainer(); } + _.each(afGui.meta.elements, function(element) { + if (element.directive) { + genericElements.push(element.directive); + } + }); }; this.sortableOptions = { @@ -337,6 +343,9 @@ if (node['#tag'] && (node['#tag'].slice(0, 19) === 'crm-search-display-')) { return 'searchDisplay'; } + if (node['#tag'] && _.includes(genericElements, node['#tag'])) { + return 'generic'; + } var classes = afGui.splitClass(node['class']), types = ['af-container', 'af-text', 'af-button', 'af-markup'], type = _.intersection(types, classes); diff --git a/ext/afform/admin/ang/afGuiEditor/elements/afGuiContainer.html b/ext/afform/admin/ang/afGuiEditor/elements/afGuiContainer.html index c98ec2297e8a..9d6431cc08ee 100644 --- a/ext/afform/admin/ang/afGuiEditor/elements/afGuiContainer.html +++ b/ext/afform/admin/ang/afGuiEditor/elements/afGuiContainer.html @@ -34,6 +34,7 @@ + diff --git a/ext/afform/admin/ang/afGuiEditor/elements/afGuiGenericElement-menu.html b/ext/afform/admin/ang/afGuiEditor/elements/afGuiGenericElement-menu.html new file mode 100644 index 000000000000..c7319d50697e --- /dev/null +++ b/ext/afform/admin/ang/afGuiEditor/elements/afGuiGenericElement-menu.html @@ -0,0 +1 @@ +
  • {{:: ts('Remove %1', {1: $ctrl.getTitle()}) }}
  • diff --git a/ext/afform/admin/ang/afGuiEditor/elements/afGuiGenericElement.html b/ext/afform/admin/ang/afGuiEditor/elements/afGuiGenericElement.html new file mode 100644 index 000000000000..f4d8445239ed --- /dev/null +++ b/ext/afform/admin/ang/afGuiEditor/elements/afGuiGenericElement.html @@ -0,0 +1,14 @@ +
    +
    +
    + {{:: $ctrl.getTitle() }} +
    + + +
    +
    +
    +
    + diff --git a/ext/afform/admin/ang/afGuiEditor/elements/afGuiGenericElement.js b/ext/afform/admin/ang/afGuiEditor/elements/afGuiGenericElement.js new file mode 100644 index 000000000000..d6bd7eabf66e --- /dev/null +++ b/ext/afform/admin/ang/afGuiEditor/elements/afGuiGenericElement.js @@ -0,0 +1,33 @@ +// https://civicrm.org/licensing +(function(angular, $, _) { + "use strict"; + + // Generic element handler for element types supplied by 3rd-party extensions + // If they have no configuration options they can use the generic template, + // or they can supply their own `admin_tpl` path. + angular.module('afGuiEditor').component('afGuiGenericElement', { + template: '
    ', + bindings: { + node: '=', + deleteThis: '&' + }, + controller: function($scope, afGui) { + var ts = $scope.ts = CRM.ts('org.civicrm.afform_admin'), + ctrl = this, + elementType = {}; + + this.$onInit = function() { + elementType = _.findWhere(afGui.meta.elements, {directive: ctrl.node['#tag']}); + }; + + this.getTemplate = function() { + return elementType.admin_tpl || '~/afGuiEditor/elements/afGuiGenericElement.html'; + }; + + this.getTitle = function() { + return elementType.title; + }; + } + }); + +})(angular, CRM.$, CRM._); diff --git a/ext/afform/core/ang/af/afForm.component.js b/ext/afform/core/ang/af/afForm.component.js index 097ebbb46e0c..e13ea5dae67f 100644 --- a/ext/afform/core/ang/af/afForm.component.js +++ b/ext/afform/core/ang/af/afForm.component.js @@ -9,7 +9,7 @@ }, controller: function($scope, $element, $timeout, crmApi4, crmStatus, $window, $location, $parse, FileUploader) { var schema = {}, - data = {}, + data = {extra: {}}, status, args, submissionResponse,