diff --git a/CRM/Core/Resources/Common.php b/CRM/Core/Resources/Common.php index bb09a9cdff49..91f0a684fea8 100644 --- a/CRM/Core/Resources/Common.php +++ b/CRM/Core/Resources/Common.php @@ -206,6 +206,7 @@ protected static function coreResourceList($region) { "js/crm.datepicker.js", "js/crm.ajax.js", "js/wysiwyg/crm.wysiwyg.js", + "js/crm.elements.js", ]; // Dynamic localization script diff --git a/CRM/Core/xml/Menu/Misc.xml b/CRM/Core/xml/Menu/Misc.xml index 3513292ddeff..1aaed44dbfc3 100644 --- a/CRM/Core/xml/Menu/Misc.xml +++ b/CRM/Core/xml/Menu/Misc.xml @@ -284,4 +284,9 @@ CRM_Contact_Form_Task_Delete access CiviCRM + + civicrm/elements + Civi\Core\Elements::get + *always allow* + diff --git a/CRM/Custom/Form/Field.php b/CRM/Custom/Form/Field.php index 6b683875370b..ee8107aecc51 100644 --- a/CRM/Custom/Form/Field.php +++ b/CRM/Custom/Form/Field.php @@ -110,8 +110,8 @@ public function preProcess() { CRM_Core_Error::statusBounce("You cannot add or edit fields in a reserved custom field-set."); } - // Add crm-options-repeat web component. FIXME: need an autoloader for web components. - \Civi::resources()->addScriptFile('civicrm', 'js/CrmOptionsRepeat.js'); + // Add crm-options-repeat web component. FIXME: autoload + \Civi::resources()->addScript('CRM.loadElement("civi-options-repeat")', ['weight' => -100]); if ($this->_gid) { $url = CRM_Utils_System::url('civicrm/admin/custom/group/field', diff --git a/Civi/Core/Elements.php b/Civi/Core/Elements.php new file mode 100644 index 000000000000..33f1f8564f1c --- /dev/null +++ b/Civi/Core/Elements.php @@ -0,0 +1,56 @@ +getQueryParams(); + $element = explode('/', $query['q'])[2]; + $locale = $query['locale'] ?? NULL; + + // TODO cache control? + $headers = []; + +// load css/js alongside the template? +// inserting +// +// HTML; + + $body = self::renderTemplate($element, $locale); + + return new Response(200, $headers, $body); + + } + + protected static function renderTemplate(string $element, ?string $locale = NULL): string { + if ($locale) { + try { + \CRM_Core_I18n::singleton()->setLocale($locale); + } + catch (\Throwable $e) { + // just use default + } + } + try { + return \CRM_Core_Smarty::singleton()->fetch("elements/{$element}.tpl"); + } + catch (\Throwable $e) { + return ''; + } + } + +} diff --git a/js/CrmOptionsRepeat.js b/elements/civi-options-repeat.js similarity index 69% rename from js/CrmOptionsRepeat.js rename to elements/civi-options-repeat.js index c2be6bcbbd60..d4b075e67033 100644 --- a/js/CrmOptionsRepeat.js +++ b/elements/civi-options-repeat.js @@ -1,62 +1,6 @@ class CrmOptionsRepeat extends HTMLElement { - static template = ` - - - - - - - - - - - - - - - - - - - - - - - - - - - -
{ts}Default{/ts} - {ts}Label{/ts} - - - {ts}Sort by label{/ts} - - - {ts}Value{/ts} - - - {ts}Sort by value{/ts} - - {ts}Enabled{/ts}
- - - {ts}Change order{/ts} - - - - - {ts}Delete{/ts} - -
- -
- `; + static tag = 'civi-options-repeat'; constructor() { super(); @@ -73,12 +17,16 @@ class CrmOptionsRepeat extends HTMLElement { } } + renderTemplate() { + const template = document.querySelector('template#' + this.constructor.tag); + this.append(document.importNode(template.content, true)); + } init() { // TODO: use this element's value attribute this.hiddenInput = this.previousElementSibling; - this.innerHTML = CrmOptionsRepeat.template; + this.renderTemplate(); this.table = this.querySelector('table tbody'); diff --git a/js/crm.elements.js b/js/crm.elements.js new file mode 100644 index 000000000000..2aea76e5ce55 --- /dev/null +++ b/js/crm.elements.js @@ -0,0 +1,18 @@ +CRM = CRM || {}; + +// TODO: merge into elements mixin autoloader +CRM.loadElement = (tagName) => { + + // load template first, so the JS doesn't have to wait for it + // TODO: skip if no template + fetch(CRM.url(`civicrm/elements/${tagName}`)) + .then((response) => response.text()) + .then((content) => { + template = document.createElement('template'); + template.id = tagName; + template.innerHTML= content; + document.body.append(template); + }) + // now load the custom element definition + .then(() => import(`${CRM.resourceUrls.civicrm}/elements/${tagName}.js`)); +} \ No newline at end of file diff --git a/templates/elements/civi-options-repeat.tpl b/templates/elements/civi-options-repeat.tpl new file mode 100644 index 000000000000..8e9d0d382e83 --- /dev/null +++ b/templates/elements/civi-options-repeat.tpl @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
{ts}Default{/ts} + {ts}Label{/ts} + + + {ts}Sort by label{/ts} + + + {ts}Value{/ts} + + + {ts}Sort by value{/ts} + + {ts}Enabled{/ts}
+ + + {ts}Change order{/ts} + + + + + {ts}Delete{/ts} + +
+ +
\ No newline at end of file