From b09b6d68638cd9ce9acb27c021a3545e97d0934f Mon Sep 17 00:00:00 2001 From: Sam Georges Date: Thu, 3 Jul 2014 18:35:35 +1000 Subject: [PATCH] Improved naming onReload -> onRefresh Improved Record finder --- modules/backend/assets/css/october.css | 10 +- .../backend/assets/less/controls/forms.less | 10 +- modules/backend/behaviors/FormController.php | 24 ++++ modules/backend/behaviors/ListController.php | 4 +- modules/backend/classes/Controller.php | 3 + modules/backend/formwidgets/RecordFinder.php | 134 ++++++++++++++++-- modules/backend/formwidgets/Relation.php | 34 ++--- .../datagrid/partials/_datagrid.htm | 4 +- .../recordfinder/assets/js/recordfinder.js | 81 +++++++++++ .../recordfinder/partials/_recordfinder.htm | 33 ++++- .../partials/_recordfinder_form.htm | 19 +++ modules/backend/widgets/Form.php | 28 +++- modules/backend/widgets/Lists.php | 10 +- .../widgets/form/partials/_form-container.htm | 2 +- .../form/partials/_section-container.htm | 2 +- 15 files changed, 335 insertions(+), 63 deletions(-) create mode 100644 modules/backend/formwidgets/recordfinder/assets/js/recordfinder.js create mode 100644 modules/backend/formwidgets/recordfinder/partials/_recordfinder_form.htm diff --git a/modules/backend/assets/css/october.css b/modules/backend/assets/css/october.css index 923a78499..44e8e8806 100644 --- a/modules/backend/assets/css/october.css +++ b/modules/backend/assets/css/october.css @@ -8249,7 +8249,6 @@ label { background: transparent; border-color: transparent; height: auto; - /*min-height: 38px;*/ } .field-recordfinder .btn { position: absolute; @@ -8257,8 +8256,7 @@ label { top: 50%; margin-top: -44px; height: 88px; - width: 46px; - text-align: center; + width: 36px; } .field-recordfinder .btn:before { content: ''; @@ -8267,9 +8265,9 @@ label { height: 0; border-top: 44px solid transparent; border-bottom: 44px solid transparent; - border-right: 36px solid #e3e3e3; + border-right: 26px solid #e3e3e3; position: absolute; - left: -26px; + left: -16px; top: 50%; margin-top: -44px; } @@ -8283,7 +8281,7 @@ label { height: 0; border-top: 44px solid transparent; border-bottom: 44px solid transparent; - border-right: 36px solid #cfcfcf; + border-right: 26px solid #cfcfcf; } .form-buttons { padding-bottom: 20px; diff --git a/modules/backend/assets/less/controls/forms.less b/modules/backend/assets/less/controls/forms.less index 003ce174d..21c46a81d 100644 --- a/modules/backend/assets/less/controls/forms.less +++ b/modules/backend/assets/less/controls/forms.less @@ -200,7 +200,6 @@ label { background: transparent; border-color: transparent; height: auto; - /*min-height: 38px;*/ } .btn { position: absolute; @@ -208,12 +207,11 @@ label { top: 50%; margin-top: -44px; height: 88px; - width: 46px; - text-align: center; + width: 36px; &:before { - .triangle(left, 36px, 88px, @btn-default-bg); + .triangle(left, 26px, 88px, @btn-default-bg); position: absolute; - left: -26px; + left: -16px; top: 50%; margin-top: -44px; } @@ -222,7 +220,7 @@ label { &:active, &.active { &:before { - .triangle(left, 36px, 88px, darken(@btn-default-bg, 8%)); + .triangle(left, 26px, 88px, darken(@btn-default-bg, 8%)); } } } diff --git a/modules/backend/behaviors/FormController.php b/modules/backend/behaviors/FormController.php index 2315e9e5f..ed141076a 100644 --- a/modules/backend/behaviors/FormController.php +++ b/modules/backend/behaviors/FormController.php @@ -87,6 +87,14 @@ class FormController extends ControllerBehavior $this->controller->formExtendFields($host); }); + $this->formWidget->bindEvent('form.refreshBefore', function($host, $saveData) { + return $this->controller->formExtendRefreshData($host, $saveData); + }); + + $this->formWidget->bindEvent('form.refresh', function($host, $result) { + return $this->controller->formExtendRefreshResults($host, $result); + }); + $this->formWidget->bindToController(); /* @@ -509,6 +517,22 @@ class FormController extends ControllerBehavior */ public function formExtendFields($host) {} + /** + * Called before the form is refreshed, should return an array of additional save data. + * @param Backend\Widgets\Form $host The hosting form widget + * @param array $saveData Current save data + * @return array + */ + public function formExtendRefreshData($host, $saveData) {} + + /** + * Called after the form is refreshed, should return an array of additional result parameters. + * @param Backend\Widgets\Form $host The hosting form widget + * @param array $result Current result parameters. + * @return array + */ + public function formExtendRefreshResults($host, $result) {} + /** * Extend supplied model used by create and update actions, the model can * be altered by overriding it in the controller. diff --git a/modules/backend/behaviors/ListController.php b/modules/backend/behaviors/ListController.php index bae1cb888..0a96c8c5e 100644 --- a/modules/backend/behaviors/ListController.php +++ b/modules/backend/behaviors/ListController.php @@ -164,7 +164,7 @@ class ListController extends ControllerBehavior if ($searchWidget = $toolbarWidget->getSearchWidget()) { $searchWidget->bindEvent('search.submit', function() use ($widget, $searchWidget) { $widget->setSearchTerm($searchWidget->getActiveTerm()); - return $widget->onRender(); + return $widget->onRefresh(); }); // Find predefined search term @@ -224,7 +224,7 @@ class ListController extends ControllerBehavior if (!$definition || !isset($this->listDefinitions[$definition])) $definition = $this->primaryDefinition; - return $this->listWidgets[$definition]->onRender(); + return $this->listWidgets[$definition]->onRefresh(); } // diff --git a/modules/backend/classes/Controller.php b/modules/backend/classes/Controller.php index 2e072068a..68b875f37 100644 --- a/modules/backend/classes/Controller.php +++ b/modules/backend/classes/Controller.php @@ -401,6 +401,9 @@ class Controller extends Extendable */ $this->pageAction(); + if ($this->fatalError) + throw new SystemException($this->fatalError); + if (!isset($this->widget->{$widgetName})) throw new SystemException(Lang::get('backend::lang.widget.not_bound', ['name'=>$widgetName])); diff --git a/modules/backend/formwidgets/RecordFinder.php b/modules/backend/formwidgets/RecordFinder.php index 1eebc7240..86349931b 100644 --- a/modules/backend/formwidgets/RecordFinder.php +++ b/modules/backend/formwidgets/RecordFinder.php @@ -11,8 +11,8 @@ use Backend\Classes\FormWidgetBase; * type: recordfinder * list: @/plugins/rainlab/user/models/user/columns.yaml * prompt: Click the Find button to find a user - * displayName: name - * displayDescription: email + * nameColumn: name + * descriptionColumn: email * * @package october\backend * @author Alexey Bobkov, Samuel Georges @@ -24,23 +24,65 @@ class RecordFinder extends FormWidgetBase */ public $defaultAlias = 'recordfinder'; + /** + * @var string Relationship type + */ + public $relationType; + + /** + * @var string Relationship name + */ + public $relationName; + + /** + * @var Model Relationship model + */ + public $relationModel; + + /** + * @var string Field name to use for key. + */ + public $keyField = 'id'; + /** * @var string Relation column to display for the name */ - public $displayName; + public $nameColumn; /** * @var string Relation column to display for the description */ - public $displayDescription; + public $descriptionColumn; + + /** + * @var string Prompt to display if no record is selected. + */ + public $prompt; + + /** + * @var Backend\Classes\WidgetBase Reference to the widget used for viewing (list or form). + */ + protected $listWidget; /** * {@inheritDoc} */ public function init() { - $this->displayName = $this->getConfig('displayName', $this->displayName); - $this->displayDescription = $this->getConfig('displayDescription', $this->displayDescription); + $this->relationName = $this->formField->columnName; + $this->relationType = $this->model->getRelationType($this->relationName); + + $this->prompt = $this->getConfig('prompt', 'Click the %s button to find a record'); + $this->keyField = $this->getConfig('keyField', $this->keyField); + $this->nameColumn = $this->getConfig('nameColumn', $this->nameColumn); + $this->descriptionColumn = $this->getConfig('descriptionColumn', $this->descriptionColumn); + + if (!$this->model->hasRelation($this->relationName)) + throw new SystemException(Lang::get('backend::lang.model.missing_relation', ['class'=>get_class($this->controller), 'relation'=>$this->relationName])); + + if (post('recordfinder_flag')) { + $this->listWidget = $this->makeListWidget(); + } } /** @@ -52,18 +94,25 @@ class RecordFinder extends FormWidgetBase return $this->makePartial('container'); } + public function onRefresh() + { + $this->model->{$this->columnName} = post($this->formField->getName()); + $this->prepareVars(); + return ['#'.$this->getId('container') => $this->makePartial('recordfinder')]; + } + /** * Prepares the list data */ public function prepareVars() { - $this->vars['name'] = $this->formField->getName(); - - $value = $this->model->{$this->columnName}; - - $this->vars['value'] = $value ?: ''; - $this->vars['displayName'] = $this->displayName; - $this->vars['displayDescription'] = $this->displayDescription; + $this->relationModel = $this->model->{$this->columnName}; + $this->vars['value'] = $this->getKeyValue(); + $this->vars['field'] = $this->formField; + $this->vars['nameValue'] = $this->getNameValue(); + $this->vars['descriptionValue'] = $this->getDescriptionValue(); + $this->vars['listWidget'] = $this->listWidget; + $this->vars['prompt'] = str_replace('%s', '', $this->prompt); } /** @@ -71,7 +120,7 @@ class RecordFinder extends FormWidgetBase */ public function loadAssets() { - + $this->addJs('js/recordfinder.js', 'core'); } /** @@ -79,6 +128,61 @@ class RecordFinder extends FormWidgetBase */ public function getSaveData($value) { - return $value; + return strlen($value) ? $value : null; + } + + public function getKeyValue() + { + if (!$this->relationModel) + return null; + + return $this->relationModel->{$this->keyField}; + } + + public function getNameValue() + { + if (!$this->relationModel || !$this->nameColumn) + return null; + + return $this->relationModel->{$this->nameColumn}; + } + + public function getDescriptionValue() + { + if (!$this->relationModel || !$this->descriptionColumn) + return null; + + return $this->relationModel->{$this->descriptionColumn}; + } + + public function onFindRecord() + { + $this->prepareVars(); + return $this->makePartial('recordfinder_form'); + } + + protected function makeListWidget() + { + $config = $this->makeConfig($this->getConfig('list')); + $config->model = $this->model->makeRelation($this->relationName); + $config->alias = $this->alias . 'List'; + $config->showSetup = false; + $config->showCheckboxes = false; + $config->recordOnClick = sprintf("$('#%s').recordFinder('updateRecord', this, ':id')", $this->getId()); + $widget = $this->makeWidget('Backend\Widgets\Lists', $config); + + // $widget->bindEvent('list.extendQueryBefore', function($host, $query) { + + // /* + // * Where not in the current list of related records + // */ + // $existingIds = $this->findExistingRelationIds(); + // if (count($existingIds)) { + // $query->whereNotIn('id', $existingIds); + // } + + // }); + + return $widget; } } \ No newline at end of file diff --git a/modules/backend/formwidgets/Relation.php b/modules/backend/formwidgets/Relation.php index b1e4e204b..728844e60 100644 --- a/modules/backend/formwidgets/Relation.php +++ b/modules/backend/formwidgets/Relation.php @@ -86,34 +86,34 @@ class Relation extends FormWidgetBase */ protected function makeRenderFormField() { - $field = clone $this->formField; - $relationObj = $this->model->{$this->relationName}(); - $relatedObj = $this->model->makeRelation($this->relationName); - $query = $relatedObj->newQuery(); + $field = clone $this->formField; + $relationObj = $this->model->{$this->relationName}(); + $relatedObj = $this->model->makeRelation($this->relationName); + $query = $relatedObj->newQuery(); - if (in_array($this->relationType, ['belongsToMany', 'morphToMany', 'morphedByMany'])) { + if (in_array($this->relationType, ['belongsToMany', 'morphToMany', 'morphedByMany'])) { $field->type = 'checkboxlist'; $field->value = $relationObj->getRelatedIds(); - } - else if ($this->relationType == 'belongsTo') { + } + else if ($this->relationType == 'belongsTo') { $field->type = 'dropdown'; $field->placeholder = $this->emptyOption; $foreignKey = $relationObj->getForeignKey(); $field->value = $this->model->$foreignKey; - } - - // It is safe to assume that if the model and related model are of - // the exact same class, then it cannot be related to itself - if ($this->model->exists && (get_class($this->model) == get_class($relatedObj))) { - $query->where($relatedObj->getKeyName(), '<>', $this->model->id); - } + } - if (in_array('October\Rain\Database\Traits\NestedTree', class_uses($relatedObj))) + // It is safe to assume that if the model and related model are of + // the exact same class, then it cannot be related to itself + if ($this->model->exists && (get_class($this->model) == get_class($relatedObj))) { + $query->where($relatedObj->getKeyName(), '<>', $this->model->id); + } + + if (in_array('October\Rain\Database\Traits\NestedTree', class_uses($relatedObj))) $field->options = $query->listsNested($this->nameColumn, $relatedObj->getKeyName()); - else + else $field->options = $query->lists($this->nameColumn, $relatedObj->getKeyName()); - return $this->renderFormField = $field; + return $this->renderFormField = $field; } /** diff --git a/modules/backend/formwidgets/datagrid/partials/_datagrid.htm b/modules/backend/formwidgets/datagrid/partials/_datagrid.htm index 33d16d8bc..f8cb23918 100644 --- a/modules/backend/formwidgets/datagrid/partials/_datagrid.htm +++ b/modules/backend/formwidgets/datagrid/partials/_datagrid.htm @@ -9,13 +9,13 @@ style="width:100%" class="control-datagrid" data-control="datagrid" - data-data-locker="#getId('datalocker') ?>" + data-data-locker="#getId('dataLocker') ?>" data-autocomplete-handler="getEventHandler('onAutocomplete') ?>" > diff --git a/modules/backend/formwidgets/recordfinder/assets/js/recordfinder.js b/modules/backend/formwidgets/recordfinder/assets/js/recordfinder.js new file mode 100644 index 000000000..d872e5a4a --- /dev/null +++ b/modules/backend/formwidgets/recordfinder/assets/js/recordfinder.js @@ -0,0 +1,81 @@ +/* + * RecordFinder plugin + * + * Data attributes: + * - data-control="recordfinder" - enables the plugin on an element + * - data-option="value" - an option with a value + * + * JavaScript API: + * $('a#someElement').recordFinder({ option: 'value' }) + * + * Dependences: + * - Some other plugin (filename.js) + */ + ++function ($) { "use strict"; + + // RECORDFINDER CLASS DEFINITION + // ============================ + + var RecordFinder = function(element, options) { + var self = this + this.options = options + this.$el = $(element) + } + + RecordFinder.DEFAULTS = { + refreshHandler: null, + dataLocker: null + } + + RecordFinder.prototype.updateRecord = function(linkEl, recordId) { + if (!this.options.dataLocker) return + var self = this + $(this.options.dataLocker).val(recordId) + + this.$el.request(this.options.refreshHandler, { + success: function(data) { + this.success(data) + $(self.options.dataLocker).trigger('change') + } + }) + + $(linkEl).closest('.recordfinder-popup').popup('hide') + } + + // RECORDFINDER PLUGIN DEFINITION + // ============================ + + var old = $.fn.recordFinder + + $.fn.recordFinder = function (option) { + var args = Array.prototype.slice.call(arguments, 1), result + this.each(function () { + var $this = $(this) + var data = $this.data('oc.recordfinder') + var options = $.extend({}, RecordFinder.DEFAULTS, $this.data(), typeof option == 'object' && option) + if (!data) $this.data('oc.recordfinder', (data = new RecordFinder(this, options))) + if (typeof option == 'string') result = data[option].apply(data, args) + if (typeof result != 'undefined') return false + }) + + return result ? result : this + } + + $.fn.recordFinder.Constructor = RecordFinder + + // RECORDFINDER NO CONFLICT + // ================= + + $.fn.recordFinder.noConflict = function () { + $.fn.recordFinder = old + return this + } + + // RECORDFINDER DATA-API + // =============== + $(document).render(function () { + $('[data-control="recordfinder"]').recordFinder() + }) + +}(window.jQuery); diff --git a/modules/backend/formwidgets/recordfinder/partials/_recordfinder.htm b/modules/backend/formwidgets/recordfinder/partials/_recordfinder.htm index 27ff85366..8f6431a63 100644 --- a/modules/backend/formwidgets/recordfinder/partials/_recordfinder.htm +++ b/modules/backend/formwidgets/recordfinder/partials/_recordfinder.htm @@ -1,7 +1,32 @@ -
+
- - Click the button to find a user + + + +
+ + + +
- + + +
\ No newline at end of file diff --git a/modules/backend/formwidgets/recordfinder/partials/_recordfinder_form.htm b/modules/backend/formwidgets/recordfinder/partials/_recordfinder_form.htm new file mode 100644 index 000000000..5519b19bc --- /dev/null +++ b/modules/backend/formwidgets/recordfinder/partials/_recordfinder_form.htm @@ -0,0 +1,19 @@ +
+ + + + render() ?> + + + +
\ No newline at end of file diff --git a/modules/backend/widgets/Form.php b/modules/backend/widgets/Form.php index a52f0f031..66b85cc54 100644 --- a/modules/backend/widgets/Form.php +++ b/modules/backend/widgets/Form.php @@ -248,11 +248,24 @@ class Form extends WidgetBase /** * Event handler for refreshing the form. */ - public function onRender() + public function onRefresh() { - $this->setFormValues(); - $this->prepareVars(); $result = []; + $saveData = $this->getSaveData(); + + /* + * Extensibility + */ + $eventResults = $this->fireEvent('form.refreshBefore', [$this, $saveData]) + Event::fire('backend.form.refreshBefore', [$this, $saveData]); + foreach ($eventResults as $eventResult) + $saveData = $eventResult + $saveData; + + /* + * Set the form variables and prepare the widget + */ + $this->setFormValues($saveData); + $this->prepareVars(); + /* * If an array of fields is supplied, update specified fields individually. @@ -264,7 +277,7 @@ class Form extends WidgetBase continue; $fieldObject = $this->allFields[$field]; - $result['#' . $fieldObject->getId('group')] = $this->renderField($fieldObject); + $result['#' . $fieldObject->getId('group')] = $this->makePartial('field', ['field' => $fieldObject]); } } @@ -274,6 +287,13 @@ class Form extends WidgetBase if (empty($result)) $result = ['#'.$this->getId() => $this->makePartial('form')]; + /* + * Extensibility + */ + $eventResults = $this->fireEvent('form.refresh', [$this, $result]) + Event::fire('backend.form.refresh', [$this, $result]); + foreach ($eventResults as $eventResult) + $result = $eventResult + $result; + return $result; } diff --git a/modules/backend/widgets/Lists.php b/modules/backend/widgets/Lists.php index 015b4fa92..5d5a2e77c 100644 --- a/modules/backend/widgets/Lists.php +++ b/modules/backend/widgets/Lists.php @@ -211,7 +211,7 @@ class Lists extends WidgetBase /** * Event handler for refreshing the list. */ - public function onRender() + public function onRefresh() { $this->prepareVars(); return ['#'.$this->getId() => $this->makePartial('list')]; @@ -223,7 +223,7 @@ class Lists extends WidgetBase public function onPaginate() { App::make('paginator')->setCurrentPage(post('page')); - return $this->onRender(); + return $this->onRefresh(); } /** @@ -760,7 +760,7 @@ class Lists extends WidgetBase */ App::make('paginator')->setCurrentPage(post('page')); - return $this->onRender(); + return $this->onRefresh(); } } @@ -867,7 +867,7 @@ class Lists extends WidgetBase $this->putSession('order', post('column_order')); $this->putSession('per_page', post('records_per_page', $this->recordsPerPage)); - return $this->onRender(); + return $this->onRefresh(); } /** @@ -938,7 +938,7 @@ class Lists extends WidgetBase public function onToggleTreeNode() { $this->putSession('tree_node_status_' . post('node_id'), post('status') ? 0 : 1); - return $this->onRender(); + return $this->onRefresh(); } } \ No newline at end of file diff --git a/modules/backend/widgets/form/partials/_form-container.htm b/modules/backend/widgets/form/partials/_form-container.htm index e6791bd7a..119185e62 100644 --- a/modules/backend/widgets/form/partials/_form-container.htm +++ b/modules/backend/widgets/form/partials/_form-container.htm @@ -1,6 +1,6 @@
diff --git a/modules/backend/widgets/form/partials/_section-container.htm b/modules/backend/widgets/form/partials/_section-container.htm index 55187e668..8bbde73cf 100644 --- a/modules/backend/widgets/form/partials/_section-container.htm +++ b/modules/backend/widgets/form/partials/_section-container.htm @@ -1,6 +1,6 @@