mirror of
https://github.com/humhub/humhub.git
synced 2025-01-17 22:28:51 +01:00
New interface TabbedForm for activate first tab with error input (#5472)
* New interface TabbedForm for activate first tab with error input * Update CHANGELOG.md * New interface TabbedFormModel for activate first tab with error input * Test for TabbedFormModel Co-authored-by: Lucas Bartholemy <luke-@users.noreply.github.com>
This commit is contained in:
parent
a35a8f91fb
commit
154266f188
@ -3,5 +3,6 @@
|
||||
|
||||
- Fix #5434: Hide disabled next/prev buttons on guide first/last steps
|
||||
- Fix #5456: `canImpersonate` only possible for SystemAdmins
|
||||
- Enh #5472: New interface `TabbedFormModel` for activate first tab with error input
|
||||
- Enh #5224: Add reply-to email in the settings
|
||||
- Enh #5471: On the pending approval page, add grouped actions and custom columns
|
||||
|
@ -0,0 +1,42 @@
|
||||
<?php
|
||||
/**
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2021 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*/
|
||||
|
||||
namespace humhub\modules\ui\form\interfaces;
|
||||
|
||||
/**
|
||||
* Interface TabbedFormModel
|
||||
* It is related for Model classes only
|
||||
*
|
||||
* @property-read array $tabs
|
||||
*
|
||||
* @since 1.11.0
|
||||
*/
|
||||
interface TabbedFormModel
|
||||
{
|
||||
/**
|
||||
* Initialize tabs for the Form
|
||||
*
|
||||
* Example of the result:
|
||||
* [
|
||||
* [
|
||||
* 'label' => 'First tab',
|
||||
* 'view' => 'first-tab-view',
|
||||
* 'linkOptions' => ['class' => 'first-tab-style'],
|
||||
* 'fields' => ['name', 'email', 'password'], // Define all fields from the tab which may have errors after submit in order to make this tab active
|
||||
* ],
|
||||
* [
|
||||
* 'label' => 'Second tab',
|
||||
* 'view' => 'second-tab-view',
|
||||
* 'linkOptions' => ['class' => 'second-tab-style'],
|
||||
* 'fields' => ['description', 'tags'],
|
||||
* ],
|
||||
* ]
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getTabs(): array;
|
||||
}
|
64
protected/humhub/modules/ui/form/widgets/FormTabs.php
Normal file
64
protected/humhub/modules/ui/form/widgets/FormTabs.php
Normal file
@ -0,0 +1,64 @@
|
||||
<?php
|
||||
/**
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2021 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*/
|
||||
|
||||
namespace humhub\modules\ui\form\widgets;
|
||||
|
||||
use humhub\modules\ui\form\interfaces\TabbedFormModel;
|
||||
use humhub\widgets\Tabs;
|
||||
use yii\base\Model;
|
||||
|
||||
/**
|
||||
* Class TabsForm
|
||||
*
|
||||
* @since 1.11.0
|
||||
*/
|
||||
class FormTabs extends Tabs
|
||||
{
|
||||
|
||||
/**
|
||||
* @var TabbedFormModel
|
||||
*/
|
||||
public $form;
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
protected function beforeSortItems()
|
||||
{
|
||||
$this->initTabbedFormItems();
|
||||
|
||||
parent::beforeSortItems();
|
||||
}
|
||||
|
||||
private function initTabbedFormItems()
|
||||
{
|
||||
if (!($this->form instanceof TabbedFormModel && $this->form instanceof Model)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$items = $this->form->tabs;
|
||||
if (empty($items)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->items = $items;
|
||||
|
||||
if (!$this->form->hasErrors()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Find first error with field and activate that tab
|
||||
$errorFields = array_keys($this->form->getErrors());
|
||||
foreach ($this->items as $t => $tab) {
|
||||
if (!empty(array_intersect($tab['fields'], $errorFields))) {
|
||||
$this->items[$t]['active'] = true;
|
||||
// Stop on first found error
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,90 @@
|
||||
<?php
|
||||
/**
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2021 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*/
|
||||
|
||||
namespace tests\codeception\models;
|
||||
|
||||
use humhub\modules\ui\form\interfaces\TabbedFormModel;
|
||||
use yii\base\Model;
|
||||
|
||||
class TestTabbedFormModel extends Model implements TabbedFormModel
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $firstname;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $lastname;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $email;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $countryId;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $stateId;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $cityId;
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function attributeLabels()
|
||||
{
|
||||
return [
|
||||
'firstname' => 'First name',
|
||||
'lastname' => 'Last name',
|
||||
'email' => 'E-mail address',
|
||||
'countryId' => 'Country',
|
||||
'stateId' => 'State',
|
||||
'cityId' => 'City',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
[['firstname', 'lastname', 'email'], 'string'],
|
||||
[['countryId', 'stateId', 'cityId'], 'integer'],
|
||||
[['email', 'countryId'], 'required'],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getTabs(): array
|
||||
{
|
||||
return [
|
||||
[
|
||||
'label' => 'First tab',
|
||||
'view' => 'tab-first',
|
||||
'fields' => ['firstname', 'lastname', 'email'],
|
||||
],
|
||||
[
|
||||
'label' => 'Second tab',
|
||||
'view' => 'tab-second',
|
||||
'fields' => ['countryId', 'stateId', 'cityId'],
|
||||
]
|
||||
];
|
||||
}
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
<?php
|
||||
/**
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2021 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*/
|
||||
|
||||
namespace tests\codeception\unit;
|
||||
|
||||
use humhub\modules\ui\form\widgets\ActiveForm;
|
||||
use humhub\modules\ui\form\widgets\FormTabs;
|
||||
use tests\codeception\_support\HumHubDbTestCase;
|
||||
use tests\codeception\models\TestTabbedFormModel;
|
||||
|
||||
class TabbedFormTest extends HumHubDbTestCase
|
||||
{
|
||||
public function testTabbedForm()
|
||||
{
|
||||
// Create a model with not filled required fields
|
||||
$tabbedForm = new TestTabbedFormModel();
|
||||
$tabbedForm->email = 'email@test.local';
|
||||
$this->assertFalse($tabbedForm->validate());
|
||||
|
||||
// Create a form with tabs
|
||||
$form = ActiveForm::begin(['action' => '/test']);
|
||||
$tabs = new FormTabs([
|
||||
'form' => $tabbedForm,
|
||||
'viewPath' => '@ui/tests/codeception/views',
|
||||
'params' => ['form' => $form, 'tabbedForm' => $tabbedForm],
|
||||
]);
|
||||
$this->assertTrue($tabs->beforeRun());
|
||||
$result = $tabs->run();
|
||||
$tabs->afterRun($result);
|
||||
ActiveForm::end();
|
||||
|
||||
// Check the second tab is active with error in the empty field Country ID
|
||||
$this->assertArrayNotHasKey('active', $tabs->items[0]);
|
||||
$this->assertArrayHasKey('active', $tabs->items[1]);
|
||||
$this->assertTrue($tabs->items[1]['active']); // <- Second tab is active
|
||||
|
||||
$tabbedForm->countryId = 10;
|
||||
$this->assertTrue($tabbedForm->validate());
|
||||
}
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
<?php
|
||||
/**
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2021 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*/
|
||||
|
||||
use humhub\modules\ui\form\widgets\ActiveForm;
|
||||
use tests\codeception\models\TestTabbedFormModel;
|
||||
|
||||
/* @var $form ActiveForm */
|
||||
/* @var $tabbedForm TestTabbedFormModel */
|
||||
?>
|
||||
|
||||
<?= $form->field($tabbedForm, 'firstname')->textInput() ?>
|
||||
<?= $form->field($tabbedForm, 'lastname')->textInput() ?>
|
||||
<?= $form->field($tabbedForm, 'email')->textInput() ?>
|
@ -0,0 +1,17 @@
|
||||
<?php
|
||||
/**
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2021 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*/
|
||||
|
||||
use humhub\modules\ui\form\widgets\ActiveForm;
|
||||
use tests\codeception\models\TestTabbedFormModel;
|
||||
|
||||
/* @var $form ActiveForm */
|
||||
/* @var $tabbedForm TestTabbedFormModel */
|
||||
?>
|
||||
|
||||
<?= $form->field($tabbedForm, 'countryId')->textInput() ?>
|
||||
<?= $form->field($tabbedForm, 'stateId')->textInput() ?>
|
||||
<?= $form->field($tabbedForm, 'cityId')->textInput() ?>
|
@ -64,27 +64,6 @@ class Tabs extends \yii\bootstrap\Tabs
|
||||
return false;
|
||||
}
|
||||
|
||||
$index = 0;
|
||||
foreach ($this->items as $key => $item) {
|
||||
if (isset($item['view'])) {
|
||||
$view = $item['view'];
|
||||
if ($this->viewPath && strpos($view, '@') === false) {
|
||||
$view = $this->viewPath . '/'.$item['view'];
|
||||
}
|
||||
|
||||
$this->items[$key]['content'] = $this->render($view, $this->getParams($item));
|
||||
unset($item['view']);
|
||||
unset($item['params']);
|
||||
}
|
||||
|
||||
if (!isset($item['sortOrder'])) {
|
||||
// keep stable sorting by adding counter (otherwise equal sorOrders will destroy index ordering)
|
||||
$this->items[$key]['sortOrder'] = 1000 + ($index * 10);
|
||||
}
|
||||
|
||||
$index++;
|
||||
}
|
||||
|
||||
$this->sortItems();
|
||||
|
||||
return true;
|
||||
@ -135,11 +114,40 @@ class Tabs extends \yii\bootstrap\Tabs
|
||||
$this->items[] = $item;
|
||||
}
|
||||
|
||||
/**
|
||||
* Before sorts the items
|
||||
*/
|
||||
protected function beforeSortItems()
|
||||
{
|
||||
$index = 0;
|
||||
foreach ($this->items as $key => $item) {
|
||||
if (isset($item['view'])) {
|
||||
$view = $item['view'];
|
||||
if ($this->viewPath && strpos($view, '@') === false) {
|
||||
$view = $this->viewPath . '/'.$item['view'];
|
||||
}
|
||||
|
||||
$this->items[$key]['content'] = $this->render($view, $this->getParams($item));
|
||||
unset($item['view']);
|
||||
unset($item['params']);
|
||||
}
|
||||
|
||||
if (!isset($item['sortOrder'])) {
|
||||
// keep stable sorting by adding counter (otherwise equal sorOrders will destroy index ordering)
|
||||
$this->items[$key]['sortOrder'] = 1000 + ($index * 10);
|
||||
}
|
||||
|
||||
$index++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sorts the item attribute by sortOrder
|
||||
*/
|
||||
private function sortItems()
|
||||
{
|
||||
$this->beforeSortItems();
|
||||
|
||||
usort($this->items, function ($a, $b) {
|
||||
if ($a['sortOrder'] == $b['sortOrder']) {
|
||||
return 0;
|
||||
|
Loading…
x
Reference in New Issue
Block a user