New event to append rules for active record (#5645)

* New event to append rules for active record

* Implement new post validation on focus field

* Revert "Implement new post validation on focus field"

This reverts commit 395917537cbfabb61e6950286ba09a60b3691e51.

* Validate post creating on focus event by AJAX

* Validate new post message on blur event by ajax request

* Fix creating of new Post

* Validate new post message on focus event by ajax request

* Skip rule "required" for post message on AJAX validation

* Move code to new module "Interaction limits"

* Clear code for creating of new post

* Remove a not used action

* Improve new comment form for event triggers

* Update CHANGELOG_DEV.md

Co-authored-by: Lucas Bartholemy <luke-@users.noreply.github.com>
This commit is contained in:
Yuriy Bakhtin 2022-06-02 17:26:31 +03:00 committed by GitHub
parent 98fa20b95c
commit e10f7854c0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 95 additions and 93 deletions

View File

@ -3,3 +3,4 @@
- Enh #5655: Possibility to archive and lock comments on global contents
- Enh #3593: Allow SSO provider to register and auto create username on registration
- Enh #5695: Truncate long profile texts in People cards
- Enh #5602: Added API to inject additional validation rules by modules on demand

View File

@ -11,7 +11,9 @@ namespace humhub\components;
use Yii;
use humhub\modules\user\models\User;
use humhub\modules\file\components\FileManager;
use yii\base\InvalidConfigException;
use yii\db\Expression;
use yii\validators\Validator;
/**
* Description of ActiveRecord
@ -35,6 +37,11 @@ class ActiveRecord extends \yii\db\ActiveRecord
*/
public $fileManagerEnableHistory = false;
/**
* @event Event is used to append rules what defined in [[rules()]].
*/
const EVENT_APPEND_RULES = 'appendRules';
/**
* @inheritdoc
*/
@ -183,4 +190,30 @@ class ActiveRecord extends \yii\db\ActiveRecord
{
return $attribute === null ? '' : parent::getAttributeLabel($attribute);
}
/**
* @inheritdoc
*/
public function createValidators()
{
$validators = parent::createValidators();
$event = new Event();
$this->trigger(self::EVENT_APPEND_RULES, $event);
if (is_array($event->result)) {
foreach ($event->result as $rule) {
if ($rule instanceof Validator) {
$validators->append($rule);
} elseif (is_array($rule) && isset($rule[0], $rule[1])) { // attributes, validator type
$validator = Validator::createValidator($rule[1], $this, (array)$rule[0], array_slice($rule, 2));
$validators->append($validator);
} else {
throw new InvalidConfigException('Invalid validation rule: a rule must specify both attribute names and validator type.');
}
}
}
return $validators;
}
}

View File

@ -77,6 +77,7 @@ class Form extends Widget
if (!$this->model) {
$this->model = new CommentModel();
$this->model->setPolyMorphicRelation($this->object);
}
return $this->render('form', [

View File

@ -48,6 +48,7 @@ $placeholder = ($isNestedComment)
<div class="comment-create-input-group">
<?= $form->field($model, 'message')->widget(RichTextField::class, [
'id' => 'newCommentForm_' . $id,
'form' => $form,
'layout' => RichTextField::LAYOUT_INLINE,
'pluginOptions' => ['maxHeight' => '300px'],
'mentioningUrl' => $mentioningUrl,

View File

@ -20,14 +20,10 @@ humhub.module('content.form', function(module, require, $) {
object.inherits(CreateForm, Widget);
CreateForm.prototype.init = function() {
var that = this;
this.$.hide();
// Hide options by default
$('.contentForm_options').hide();
$('#contentFormError').hide();
this.setDefaultVisibility();
this.$.fadeIn('fast');
@ -46,8 +42,9 @@ humhub.module('content.form', function(module, require, $) {
};
CreateForm.prototype.submit = function(evt) {
this.$.find("#contentFormError, .preferences, .fileinput-button").hide();
this.$.find("#contentFormError li").remove();
this.$.find('.preferences, .fileinput-button').hide();
this.$.find('.help-block-error').html('');
this.$.find('.has-error').removeClass('has-error');
var that = this;
evt.block = 'manual';
@ -116,14 +113,12 @@ humhub.module('content.form', function(module, require, $) {
};
CreateForm.prototype.handleError = function(response) {
$('#contentFormError').show();
$.each(response.errors, function(fieldName, errorMessage) {
// Mark Fields as Error
var fieldId = 'contentForm_' + fieldName;
$('#' + fieldId).addClass('error');
$.each(errorMessage, function(key, msg) {
$('#contentFormError').append('<li><i class=\"icon-warning-sign\"></i> ' + msg + '</li>');
});
var that = this;
$.each(response.errors, function(fieldName, errorMessages) {
that.$.find('.field-post-' + fieldName).addClass('has-error');
var fieldSelector = '.field-contentForm_' + fieldName;
that.$.find(fieldSelector + ', ' + fieldSelector + '_input')
.find('.help-block-error').html(errorMessages.join('<br>'));
});
};

View File

@ -61,7 +61,7 @@ humhub.module('ui.richtext.prosemirror', function(module, require, $) {
var that = this;
this.$.on('focusout', function() {
that.getInput().val(that.editor.serialize());
that.getInput().val(that.editor.serialize()).trigger('blur');
}).on('clear', function() {
that.editor.clear();
}).on('focus', function() {
@ -70,6 +70,7 @@ humhub.module('ui.richtext.prosemirror', function(module, require, $) {
this.$.find('.humhub-ui-richtext').on('focus', function() {
that.focus();
that.getInput().val(that.editor.serialize()).trigger('blur');
})
if (this.options.backupInterval) {

View File

@ -11,6 +11,7 @@ namespace humhub\modules\content\widgets;
use humhub\modules\content\permissions\CreatePublicContent;
use humhub\modules\stream\actions\StreamEntryResponse;
use humhub\modules\topic\models\Topic;
use humhub\modules\ui\form\widgets\ActiveForm;
use Yii;
use yii\web\HttpException;
use humhub\components\Widget;
@ -67,11 +68,12 @@ class WallCreateContentForm extends Widget
/**
* Returns the custom form implementation.
*
* @param ActiveForm
* @return string
*/
public function renderForm()
public function renderForm(ActiveForm $form): string
{
return "";
return '';
}
/**
@ -88,7 +90,7 @@ class WallCreateContentForm extends Widget
}
return $this->render('@humhub/modules/content/widgets/views/wallCreateContentForm', [
'form' => $this->renderForm(),
'wallCreateContentForm' => $this,
'contentContainer' => $this->contentContainer,
'submitUrl' => $this->contentContainer->createUrl($this->submitUrl),
'submitButtonText' => $this->submitButtonText,

View File

@ -118,6 +118,12 @@ class AbstractRichTextEditor extends JsInputWidget
*/
public $pluginOptions = [];
/**
* Options for field of active form
* @var array
*/
public $fieldOptions = [];
/**
* If set to true the picker will be focused automatically.
*
@ -175,7 +181,7 @@ class AbstractRichTextEditor extends JsInputWidget
$inputOptions = $this->getInputAttributes();
if ($this->form != null) {
$input = $this->form->field($this->model, $this->attribute)->textarea($inputOptions)->label(false);
$input = $this->form->field($this->model, $this->attribute, $this->fieldOptions)->textarea($inputOptions)->label(false);
$richText = Html::tag('div', $this->editOutput($this->getValue()), $this->getOptions());
$richText = $this->getLabel() . $richText;
} elseif ($this->model != null) {
@ -188,7 +194,7 @@ class AbstractRichTextEditor extends JsInputWidget
$richText = $this->getLabel() . $richText;
}
return $input . $richText . $this->prepend();
return $richText . $input . $this->prepend();
}
/**

View File

@ -1,6 +1,8 @@
<?php
use humhub\modules\content\widgets\WallCreateContentForm;
use humhub\modules\topic\widgets\TopicPicker;
use humhub\modules\ui\form\widgets\ActiveForm;
use humhub\modules\ui\icon\widgets\Icon;
use yii\helpers\Html;
use humhub\modules\content\assets\ContentFormAsset;
@ -13,9 +15,9 @@ use humhub\modules\file\widgets\UploadProgress;
use humhub\widgets\Link;
use humhub\widgets\Button;
/* @var $wallCreateContentForm WallCreateContentForm */
/* @var $defaultVisibility integer */
/* @var $submitUrl string */
/* @var $form string */
/* @var $submitButtonText string */
/* @var $fileHandlers \humhub\modules\file\handler\BaseFileHandler[] */
/* @var $canSwitchVisibility boolean */
@ -38,9 +40,9 @@ $pickerUrl = ($contentContainer instanceof Space) ? $contentContainer->createUrl
<div class="panel panel-default clearfix">
<div class="panel-body" id="contentFormBody" style="display:none;" data-action-component="content.form.CreateForm" >
<?= Html::beginForm($submitUrl, 'POST', ['data-ui-addition' => 'acknowledgeForm']); ?>
<?php $form = ActiveForm::begin(['acknowledge' => true]); ?>
<?= $form; ?>
<?= $wallCreateContentForm->renderForm($form) ?>
<div id="notifyUserContainer" class="form-group" style="margin-top: 15px;display:none;">
<?= UserPickerField::widget([
@ -64,12 +66,10 @@ $pickerUrl = ($contentContainer instanceof Space) ? $contentContainer->createUrl
<?= Html::hiddenInput("containerGuid", $contentContainer->guid); ?>
<?= Html::hiddenInput("containerClass", get_class($contentContainer)); ?>
<ul id="contentFormError"></ul>
<div class="contentForm_options">
<hr>
<div class="btn_container">
<?= Button::info($submitButtonText)->action('submit')->id('post_submit_button')->submit() ?>
<?= Button::info($submitButtonText)->action('submit', $submitUrl)->id('post_submit_button')->submit() ?>
<?php
$uploadButton = UploadButton::widget([
@ -122,7 +122,7 @@ $pickerUrl = ($contentContainer instanceof Space) ? $contentContainer->createUrl
</div>
<!-- /contentForm_Options -->
<?= Html::endForm(); ?>
<?php ActiveForm::end(); ?>
</div>
<!-- /panel body -->
</div> <!-- /panel -->

View File

@ -8,7 +8,6 @@
namespace humhub\modules\post;
use Yii;
use humhub\modules\post\models\Post;
/**

View File

@ -11,4 +11,3 @@ return [
[IntegrityController::class, IntegrityController::EVENT_ON_RUN, [Events::class, 'onIntegrityCheck']],
]
];
?>

View File

@ -64,7 +64,7 @@ class PostController extends ContentContainerController
}
$post = new Post($this->contentContainer);
$post->message = Yii::$app->request->post('message');
$post->load(Yii::$app->request->post(), 'Post');
return Post::getDb()->transaction(function ($db) use ($post) {
return WallCreateContentForm::create($post, $this->contentContainer);

View File

@ -8,15 +8,13 @@
namespace humhub\modules\post\models;
use humhub\modules\content\components\ContentContainerActiveRecord;
use humhub\modules\post\permissions\CreatePost;
use humhub\modules\post\widgets\WallEntry;
use Yii;
use humhub\libs\MarkdownPreview;
use humhub\modules\content\widgets\richtext\RichText;
use humhub\modules\content\components\ContentActiveRecord;
use humhub\modules\post\permissions\CreatePost;
use humhub\modules\post\widgets\WallEntry;
use humhub\modules\search\interfaces\Searchable;
use humhub\modules\user\models\User;
use Yii;
use yii\helpers\Url;
/**
@ -47,6 +45,11 @@ class Post extends ContentActiveRecord implements Searchable
*/
public $canMove = CreatePost::class;
/**
* Scenarios
*/
const SCENARIO_AJAX_VALIDATION = 'ajaxValidation';
/**
* @inheritdoc
*/
@ -61,7 +64,7 @@ class Post extends ContentActiveRecord implements Searchable
public function rules()
{
return [
[['message'], 'required'],
[['message'], 'required', 'except' => self::SCENARIO_AJAX_VALIDATION],
[['message'], 'string'],
[['url'], 'string', 'max' => 255]
];

View File

@ -1,48 +0,0 @@
<?php
/**
* @link https://www.humhub.org/
* @copyright Copyright (c) 2018 HumHub GmbH & Co. KG
* @license https://www.humhub.com/licences
*/
namespace humhub\modules\post\widgets;
use humhub\modules\content\widgets\WallCreateContentForm;
use humhub\modules\post\permissions\CreatePost;
/**
* This widget is used include the post form.
* It normally should be placed above a steam.
*
* @since 0.5
*/
class CreateForm extends WallCreateContentForm
{
/**
* @inheritdoc
*/
public $submitUrl = '/post/post/post';
/**
* @inheritdoc
*/
public function renderForm()
{
return $this->render('form', []);
}
/**
* @inheritdoc
*/
public function run()
{
if (!$this->contentContainer->permissionManager->can(new CreatePost())) {
return;
}
return parent::run();
}
}

View File

@ -9,8 +9,10 @@
namespace humhub\modules\post\widgets;
use humhub\modules\content\widgets\WallCreateContentForm;
use humhub\modules\post\models\Post;
use humhub\modules\post\permissions\CreatePost;
use humhub\modules\space\models\Space;
use humhub\modules\ui\form\widgets\ActiveForm;
use yii\helpers\Url;
/**
@ -35,11 +37,13 @@ class Form extends WallCreateContentForm
/**
* @inheritdoc
*/
public function renderForm()
public function renderForm(ActiveForm $form): string
{
$canCreatePostInSpace = ($this->contentContainer instanceof Space && $this->contentContainer->can(CreatePost::class));
return $this->render('form', [
'form' => $form,
'post' => new Post($this->contentContainer),
'mentioningUrl' => $canCreatePostInSpace ? Url::to([$this->mentioningUrl, 'id' => $this->contentContainer->id]) : null,
]);
}

View File

@ -1,12 +1,17 @@
<?php
use humhub\modules\content\widgets\richtext\RichTextField;
use humhub\modules\post\models\Post;
use humhub\modules\ui\form\widgets\ActiveForm;
/* @var string $mentioningUrl */
/* @var ActiveForm $form */
/* @var Post $post */
?>
<?= RichTextField::widget([
<?= $form->field($post, 'message')->widget(RichTextField::class, [
'id' => 'contentForm_message',
'form' => $form,
'layout' => RichTextField::LAYOUT_INLINE,
'pluginOptions' => ['maxHeight' => '300px'],
'placeholder' => Yii::t("PostModule.base", "What's on your mind?"),
@ -14,4 +19,4 @@ use humhub\modules\content\widgets\richtext\RichTextField;
'disabled' => (property_exists(Yii::$app->controller, 'contentContainer') && Yii::$app->controller->contentContainer->isArchived()),
'disabledText' => Yii::t("PostModule.base", "This space is archived."),
'mentioningUrl' => $mentioningUrl,
]); ?>
])->label(false) ?>

View File

@ -23,10 +23,10 @@
}
}
#contentFormError {
color: @danger;
padding-left: 0;
list-style: none;
#contentFormBody {
.form-group, .help-block-error {
margin: 0;
}
}
// Empty stream info

File diff suppressed because one or more lines are too long