Improved naming onReload -> onRefresh

Improved Record finder
This commit is contained in:
Sam Georges 2014-07-03 18:35:35 +10:00
parent bd8137ea97
commit b09b6d6863
15 changed files with 335 additions and 63 deletions

View File

@ -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;

View File

@ -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%));
}
}
}

View File

@ -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.

View File

@ -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();
}
//

View File

@ -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]));

View File

@ -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', '<i class="icon-search"></i>', $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;
}
}

View File

@ -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;
}
/**

View File

@ -9,13 +9,13 @@
style="width:100%"
class="control-datagrid"
data-control="datagrid"
data-data-locker="#<?= $this->getId('datalocker') ?>"
data-data-locker="#<?= $this->getId('dataLocker') ?>"
data-autocomplete-handler="<?= $this->getEventHandler('onAutocomplete') ?>"
></div>
<input
type="hidden"
id="<?= $this->getId('datalocker') ?>"
id="<?= $this->getId('dataLocker') ?>"
name="<?= $name ?>"
value="<?= e($value) ?>"
/>

View File

@ -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);

View File

@ -1,7 +1,32 @@
<div class="field-recordfinder">
<div
class="field-recordfinder"
data-control="recordfinder"
data-refresh-handler="<?= $this->getEventHandler('onRefresh') ?>"
data-data-locker="#<?= $field->getId() ?>"
id="<?= $this->getId() ?>">
<span class="form-control">
<!-- Hello<br /><small>sam@daftspunk.com</small> -->
<span class="text-muted">Click the <i class="icon-search"></i> button to find a user</span>
<?php if ($value): ?>
<?= $nameValue ?: 'Undefined' ?>
<?php if ($descriptionValue): ?>
<br /><small><?= $descriptionValue ?></small>
<?php endif ?>
<?php else: ?>
<span class="text-muted"><?= $prompt ?></span>
<?php endif ?>
</span>
<button class="btn btn-default" type="button"><i class="icon-search"></i></button>
<button
class="btn btn-default"
data-control="popup"
data-handler="<?= $this->getEventHandler('onFindRecord') ?>"
data-request-data="recordfinder_flag: 1"
type="button">
<i class="icon-search"></i>
</button>
<input
type="hidden"
name="<?= $field->getName() ?>"
id="<?= $field->getId() ?>"
value="<?= e($value) ?>"
/>
</div>

View File

@ -0,0 +1,19 @@
<div id="<?= $this->getId('popup') ?>" class="recordfinder-popup">
<?= Form::open() ?>
<div class="modal-header">
<button type="button" class="close" data-dismiss="popup">&times;</button>
<h4 class="modal-title">Find Record</h4>
</div>
<?= $listWidget->render() ?>
<div class="modal-footer">
<button
type="button"
class="btn btn-default"
data-dismiss="popup">
Cancel
</button>
</div>
<?= Form::close() ?>
</div>

View File

@ -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;
}

View File

@ -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();
}
}

View File

@ -1,6 +1,6 @@
<div
data-control="formwidget"
data-refresh-handler="<?= $this->getEventHandler('onRender') ?>"
data-refresh-handler="<?= $this->getEventHandler('onRefresh') ?>"
class="form-widget form-elements layout"
role="form"
id="<?= $this->getId() ?>">

View File

@ -1,6 +1,6 @@
<div
data-control="formwidget"
data-refresh-handler="<?= $this->getEventHandler('onRender') ?>"
data-refresh-handler="<?= $this->getEventHandler('onRefresh') ?>"
class="layout-row"
role="form"
id="<?= $this->getId($renderSection.'Container') ?>">