From 4704f85096037f1b08f5c754bd6e81301fa14af9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20K=C3=BCndig?= Date: Mon, 9 Dec 2019 10:45:26 +0100 Subject: [PATCH] Added lazy loading for backend form tabs (#4658) * Added lazy loading for backend form tabs --- modules/backend/classes/FormTabs.php | 9 +++++ modules/backend/widgets/Form.php | 31 ++++++++++++++++- .../widgets/form/assets/js/october.form.js | 31 ++++++++++++++++- .../widgets/form/partials/_form_tabs.htm | 25 ++++++++++---- .../widgets/form/partials/_form_tabs_lazy.htm | 33 +++++++++++++++++++ 5 files changed, 120 insertions(+), 9 deletions(-) create mode 100644 modules/backend/widgets/form/partials/_form_tabs_lazy.htm diff --git a/modules/backend/classes/FormTabs.php b/modules/backend/classes/FormTabs.php index 709a0306e..74ccae2f2 100644 --- a/modules/backend/classes/FormTabs.php +++ b/modules/backend/classes/FormTabs.php @@ -27,6 +27,11 @@ class FormTabs implements IteratorAggregate, ArrayAccess */ public $fields = []; + /** + * @var array Names of tabs to lazy load. + */ + public $lazy = []; + /** * @var string Default tab label to use when none is specified. */ @@ -106,6 +111,10 @@ class FormTabs implements IteratorAggregate, ArrayAccess if (array_key_exists('paneCssClass', $config)) { $this->paneCssClass = $config['paneCssClass']; } + + if (array_key_exists('lazy', $config)) { + $this->lazy = $config['lazy']; + } } /** diff --git a/modules/backend/widgets/Form.php b/modules/backend/widgets/Form.php index ce42ad24b..efda2e017 100644 --- a/modules/backend/widgets/Form.php +++ b/modules/backend/widgets/Form.php @@ -456,6 +456,35 @@ class Form extends WidgetBase return $result; } + /** + * Renders all fields of a tab in the target tab-pane. + * + * @return array + */ + public function onLazyLoadTab() + { + $target = post('target'); + $tabName = post('name'); + + $fields = array_get(optional($this->getTab('primary'))->fields, $tabName); + + return [ + $target => $this->makePartial('form_fields', ['fields' => $fields]), + ]; + } + + /** + * Helper method to convert a field name to a valid ID attribute. + * + * @param $input + * + * @return string + */ + public function nameToId($input) + { + return HtmlHelper::nameToId($input); + } + /** * Creates a flat array of form fields from the configuration. * Also slots fields in to their respective tabs. @@ -935,7 +964,7 @@ class Form extends WidgetBase } $widgetConfig = $this->makeConfig($field->config); - $widgetConfig->alias = $this->alias . studly_case(HtmlHelper::nameToId($field->fieldName)); + $widgetConfig->alias = $this->alias . studly_case($this->nameToId($field->fieldName)); $widgetConfig->sessionKey = $this->getSessionKey(); $widgetConfig->previewMode = $this->previewMode; $widgetConfig->model = $this->model; diff --git a/modules/backend/widgets/form/assets/js/october.form.js b/modules/backend/widgets/form/assets/js/october.form.js index 2a95c5aae..7b82f5759 100644 --- a/modules/backend/widgets/form/assets/js/october.form.js +++ b/modules/backend/widgets/form/assets/js/october.form.js @@ -34,6 +34,7 @@ this.bindDependants() this.bindCheckboxlist() this.toggleEmptyTabs() + this.bindLazyTabs() this.bindCollapsibleSections() this.$el.on('oc.triggerOn.afterUpdate', this.proxy(this.toggleEmptyTabs)) @@ -161,6 +162,34 @@ }) } + /* + * Render tab form fields once a lazy tab is selected. + */ + FormWidget.prototype.bindLazyTabs = function() { + this.$el.on('click', '.tab-lazy [data-toggle="tab"]', function() { + var $el = $(this) + $.request('form::onLazyLoadTab', { + data: { + target: $el.data('target'), + name: $el.data('tab-name'), + }, + success: function(data) { + this.success(data) + $el.parent().removeClass('tab-lazy') + // Trigger all input presets to populate new fields. + setTimeout(function() { + $('[data-input-preset]').each(function() { + var preset = $(this).data('oc.inputPreset') + if (preset && preset.$src) { + preset.$src.trigger('input') + } + }) + }, 0) + } + }) + }) + } + /* * Hides tabs that have no content, it is possible this can be * called multiple times in a single cycle due to input.trigger. @@ -184,7 +213,7 @@ /* * Check each tab pane for form field groups */ - $('.tab-pane', tabControl).each(function() { + $('.tab-pane:not(.lazy)', tabControl).each(function() { $('[data-target="#' + $(this).attr('id') + '"]', tabControl) .closest('li') .toggle(!!$('> .form-group:not(:empty):not(.hide)', $(this)).length) diff --git a/modules/backend/widgets/form/partials/_form_tabs.htm b/modules/backend/widgets/form/partials/_form_tabs.htm index 1cbddcca1..4ff1e0204 100644 --- a/modules/backend/widgets/form/partials/_form_tabs.htm +++ b/modules/backend/widgets/form/partials/_form_tabs.htm @@ -14,7 +14,10 @@
- $fields): ?> -
- makePartial('form_fields', ['fields' => $fields]) ?> -
+ $fields): + $lazy = in_array($name, $tabs->lazy); + ?> +
+ + makePartial('form_tabs_lazy', ['fields' => $fields]) ?> + + makePartial('form_fields', ['fields' => $fields]) ?> + +
diff --git a/modules/backend/widgets/form/partials/_form_tabs_lazy.htm b/modules/backend/widgets/form/partials/_form_tabs_lazy.htm new file mode 100644 index 000000000..4d7534587 --- /dev/null +++ b/modules/backend/widgets/form/partials/_form_tabs_lazy.htm @@ -0,0 +1,33 @@ +
+
+ +
+
+type, $ignoredTypes)) continue; + + $isMultiValue = is_array($field->value); + foreach (array_wrap($field->value) as $index => $value): + // Use array field names if the field has multiple values (repeater, checkboxlist, etc.). + $fieldName = $isMultiValue ? sprintf('%s[%s]', $field->getName(), $index) : $field->getName(); + + $valueIsArray = is_array($value); + foreach (array_wrap($value) as $index => $value): + // Set the correct array keys if the value is an array (repeater form fields). + $currentFieldName = $valueIsArray ? sprintf('%s[%s]', $fieldName, $index) : $fieldName; +?> + getAttributes() ?> + /> + + +