diff --git a/modules/backend/behaviors/FormController.php b/modules/backend/behaviors/FormController.php index ad9e3713b..f110ef308 100644 --- a/modules/backend/behaviors/FormController.php +++ b/modules/backend/behaviors/FormController.php @@ -125,8 +125,9 @@ class FormController extends ControllerBehavior $this->controller->formExtendFields($this->formWidget, $fields); }); - $this->formWidget->bindEvent('form.beforeRefresh', function ($saveData) { - return $this->controller->formExtendRefreshData($this->formWidget, $saveData); + $this->formWidget->bindEvent('form.beforeRefresh', function ($holder) { + $result = $this->controller->formExtendRefreshData($this->formWidget, $holder->data); + if (is_array($result)) $holder->data = $result; }); $this->formWidget->bindEvent('form.refreshFields', function ($fields) { diff --git a/modules/backend/classes/ControllerBehavior.php b/modules/backend/classes/ControllerBehavior.php index faa7452e9..4a63a8398 100644 --- a/modules/backend/classes/ControllerBehavior.php +++ b/modules/backend/classes/ControllerBehavior.php @@ -103,7 +103,7 @@ class ControllerBehavior extends ExtensionBase * Loop the remaining key parts and build a result */ foreach ($keyParts as $key) { - if (!array_key_exists($key, $result)) { + if (!is_array($result) || !array_key_exists($key, $result)) { return $default; } diff --git a/modules/backend/formwidgets/fileupload/assets/js/fileupload.js b/modules/backend/formwidgets/fileupload/assets/js/fileupload.js index 341532184..22373d752 100644 --- a/modules/backend/formwidgets/fileupload/assets/js/fileupload.js +++ b/modules/backend/formwidgets/fileupload/assets/js/fileupload.js @@ -164,6 +164,11 @@ $('.upload-remove-button', $preview).data('request-data', { file_id: response.id }) $img.attr('src', response.thumb) } + + /* + * Trigger change event (Compatability with october.form.js) + */ + this.$el.closest('[data-field-name]').trigger('change.oc.formwidget') } FileUpload.prototype.onUploadError = function(file, error) { diff --git a/modules/backend/widgets/Form.php b/modules/backend/widgets/Form.php index ced5ff95a..270c45963 100644 --- a/modules/backend/widgets/Form.php +++ b/modules/backend/widgets/Form.php @@ -287,7 +287,7 @@ class Form extends WidgetBase */ public function setFormValues($data = null) { - if ($data == null) { + if ($data === null) { $data = $this->getSaveData(); } @@ -312,12 +312,10 @@ class Form extends WidgetBase /* * Extensibility */ - $eventResults = $this->fireEvent('form.beforeRefresh', [$saveData]) + - Event::fire('backend.form.beforeRefresh', [$this, $saveData]); - - foreach ($eventResults as $eventResult) { - $saveData = $eventResult + $saveData; - } + $dataHolder = (object) ['data' => $saveData]; + $this->fireEvent('form.beforeRefresh', [$dataHolder]); + Event::fire('backend.form.beforeRefresh', [$this, $dataHolder]); + $saveData = $dataHolder->data; /* * Set the form variables and prepare the widget @@ -356,8 +354,10 @@ class Form extends WidgetBase /* * Extensibility */ - $eventResults = $this->fireEvent('form.refresh', [$result]) + - Event::fire('backend.form.refresh', [$this, $result]); + $eventResults = array_merge( + $this->fireEvent('form.refresh', [$result]), + Event::fire('backend.form.refresh', [$this, $result]) + ); foreach ($eventResults as $eventResult) { $result = $eventResult + $result; diff --git a/modules/backend/widgets/form/assets/js/october.form.js b/modules/backend/widgets/form/assets/js/october.form.js index 7295da269..3606084ff 100644 --- a/modules/backend/widgets/form/assets/js/october.form.js +++ b/modules/backend/widgets/form/assets/js/october.form.js @@ -5,22 +5,47 @@ * - Nil */ +function ($) { "use strict"; + var Base = $.oc.foundation.base, + BaseProto = Base.prototype var FormWidget = function (element, options) { + this.$el = $(element) + this.options = options || {} - var $el = this.$el = $(element); + /* + * Throttle dependency updating + */ + this.dependantUpdateInterval = 300 + this.dependantUpdateTimers = {} - this.$form = $el.closest('form') - this.options = options || {}; + $.oc.foundation.controlUtils.markDisposable(element) + Base.call(this) + this.init() + } + + FormWidget.prototype = Object.create(BaseProto) + FormWidget.prototype.constructor = FormWidget + + FormWidget.prototype.init = function() { + + this.$form = this.$el.closest('form') this.bindDependants() this.bindCheckboxlist() this.toggleEmptyTabs() this.bindCollapsibleSections() + + this.$el.one('dispose-control', this.proxy(this.dispose)) } - FormWidget.DEFAULTS = { - refreshHandler: null + FormWidget.prototype.dispose = function() { + this.$el.off('dispose-control', this.proxy(this.dispose)) + this.$el.removeData('oc.formwidget') + + this.$el = null + this.options = null + + BaseProto.dispose.call(this) } /* @@ -51,13 +76,12 @@ FormWidget.prototype.bindDependants = function() { var self = this, form = this.$el, - formEl = this.$form, fieldMap = {} /* * Map master and slave field map */ - form.find('[data-field-depends]').each(function(){ + form.find('[data-field-depends]').each(function() { var name = $(this).data('field-name'), depends = $(this).data('field-depends') @@ -73,20 +97,37 @@ * When a master is updated, refresh its slaves */ $.each(fieldMap, function(fieldName, toRefresh){ - form.find('[data-field-name="'+fieldName+'"]') - .on('change', 'select, input', function(){ - formEl.request(self.options.refreshHandler, { - data: toRefresh - }).success(function(){ - self.toggleEmptyTabs() - }) + form + .find('[data-field-name="'+fieldName+'"]') + .on('change.oc.formwidget', $.proxy(self.onRefreshDependants, self, fieldName, toRefresh)) + }) + } - $.each(toRefresh.fields, function(index, field){ - form.find('[data-field-name="'+field+'"]:visible') - .addClass('loading-indicator-container size-form-field') - .loadIndicator() - }) - }) + /* + * Refresh a dependancy field + * Uses a throttle to prevent duplicate calls and click spamming + */ + FormWidget.prototype.onRefreshDependants = function(fieldName, toRefresh) { + var self = this, + form = this.$el, + formEl = this.$form + + if (this.dependantUpdateTimers[fieldName] !== undefined) { + window.clearTimeout(this.dependantUpdateTimers[fieldName]) + } + + this.dependantUpdateTimers[fieldName] = window.setTimeout(function() { + formEl.request(self.options.refreshHandler, { + data: toRefresh + }).success(function() { + self.toggleEmptyTabs() + }) + }, this.dependantUpdateInterval) + + $.each(toRefresh.fields, function(index, field) { + form.find('[data-field-name="'+field+'"]:visible') + .addClass('loading-indicator-container size-form-field') + .loadIndicator() }) } @@ -99,7 +140,7 @@ if (!tabControl.length) return - $('.tab-pane', tabControl).each(function(){ + $('.tab-pane', tabControl).each(function() { $('[data-target="#' + $(this).attr('id') + '"]', tabControl) .toggle(!!$('.form-group:not(:empty)', $(this)).length) }) @@ -123,6 +164,10 @@ .nextUntil('.section-field').hide() } + FormWidget.DEFAULTS = { + refreshHandler: null + } + // FORM WIDGET PLUGIN DEFINITION // ============================ @@ -157,7 +202,7 @@ // FORM WIDGET DATA-API // ============== - $(document).render(function(){ + $(document).render(function() { $('[data-control="formwidget"]').formWidget(); })