diff --git a/protected/humhub/docs/CHANGELOG_DEV.md b/protected/humhub/docs/CHANGELOG_DEV.md index 8568cbe528..80bef41ddb 100644 --- a/protected/humhub/docs/CHANGELOG_DEV.md +++ b/protected/humhub/docs/CHANGELOG_DEV.md @@ -45,3 +45,4 @@ HumHub Change Log - v1.3-dev Branch - Chg: Reduced email length to 150 chars to support utf8mb4 charset - Enh: Added UI core module to group UI components - Enh: Added new IconPicker form field +- Chg: Moved form widgets from `humhub\widgets` to `humhub\modules\ui\form\widgets` (added compatibility layer) diff --git a/protected/humhub/docs/guide/developer/modules-migrate.md b/protected/humhub/docs/guide/developer/modules-migrate.md index 277c24f752..e184c756a3 100644 --- a/protected/humhub/docs/guide/developer/modules-migrate.md +++ b/protected/humhub/docs/guide/developer/modules-migrate.md @@ -23,6 +23,12 @@ The existing `humhub\components\queue\ActiveJob` is declared as deprecated and w Added new user status (User::SOFT_DELETED). You can find more information here: [Users](modules-users.md) +### Widgets + +Moved all form and field related widgets from `humhub\widgets` to `humhub\modules\ui\form\widgets` namespace. +There is a compatibility layer for the 1.3 release. + + Migrate from 1.1 to 1.2 ----------------------- @@ -128,4 +134,4 @@ No breaking changes. - Now handle ContentContainerController layouts, new option showSidebar - New ContentAddonController Class -- New Wiki Parser / Editor Widget \ No newline at end of file +- New Wiki Parser / Editor Widget diff --git a/protected/humhub/modules/content/widgets/ContentTagDropDown.php b/protected/humhub/modules/content/widgets/ContentTagDropDown.php new file mode 100644 index 0000000000..05425ff908 --- /dev/null +++ b/protected/humhub/modules/content/widgets/ContentTagDropDown.php @@ -0,0 +1,111 @@ +tagClass) { + $this->tagClass = ContentTag::class; + // Reset default behavior inf no specific tagClass is given + if ($this->type === true) { + $this->type = null; + } + } + + if (!$this->none && !$this->noneLabel) { + $this->noneLabel = Yii::t('ContentModule.widgets_ContentTagDropDown', 'None'); + } + } + + public function run() + { + $items = $this->getItems(); + + if (empty($items)) { + return; + } + + $options = $this->getOptions(); + unset($options['id']); + + if ($this->form && $this->hasModel()) { + return $this->form->field($this->model, $this->attribute)->dropDownList($items, $options); + } elseif ($this->hasModel()) { + return Html::activeDropDownList($this->model, $this->attribute, $items, $options); + } else { + return Html::dropDownList($this->name, $this->value, $items, $options); + } + } + + public function getAttributes() + { + $result = [ + 'class' => 'form-control', + 'options' => $this->itemOptions + ]; + + if ($this->prompt) { + $result['prompt'] = $this->prompt; + } + + return $result; + } + + public function getItems() + { + if ($this->items) { + return $this->items; + } + + if (!$this->query) { + if ($this->contentContainer) { + $this->query = call_user_func($this->tagClass .'::findByContainer', $this->contentContainer, $this->includeGlobal); + } elseif (!empty($this->type)) { + $type = ($this->type === true) ? $this->tagClass : $this->type; + $this->query = call_user_func($this->tagClass .'::findByType', [$type]); + } else { + $this->query = call_user_func($this->tagClass .'::find'); + } + } + + $tags = $this->items = $this->query->all(); + + $result = []; + foreach ($tags as $tag) { + $result[$tag->id] = $tag->name; + $this->itemOptions[$tag->id] = [ + 'data-type-color' => $tag->color + ]; + } + + return $result; + } + +} diff --git a/protected/humhub/modules/ui/form/widgets/ActiveField.php b/protected/humhub/modules/ui/form/widgets/ActiveField.php new file mode 100644 index 0000000000..c6431a8196 --- /dev/null +++ b/protected/humhub/modules/ui/form/widgets/ActiveField.php @@ -0,0 +1,38 @@ +model; + $config['attribute'] = $this->attribute; + $config['view'] = $this->form->getView(); + + if (isset($config['options']) && isset(class_parents($class)['humhub\widgets\InputWidget'])) { + $this->adjustLabelFor($config['options']); + } + + return parent::widget($class, $config); + } + +} diff --git a/protected/humhub/modules/ui/form/widgets/ActiveForm.php b/protected/humhub/modules/ui/form/widgets/ActiveForm.php new file mode 100644 index 0000000000..d904552886 --- /dev/null +++ b/protected/humhub/modules/ui/form/widgets/ActiveForm.php @@ -0,0 +1,31 @@ +view); + + //Only for compatibility + if (empty($this->name)) { + $this->name = $this->formName; + } + + if ($this->selection != null && !is_array($this->selection)) { + $this->selection = [$this->selection]; + } + + // Prepare current selection and selection options + $selection = []; + $selectedOptions = $this->getSelectedOptions(); + foreach ($selectedOptions as $id => $option) { + $selection[$id] = $option['data-text']; + } + + $options = $this->getOptions(); + $options['options'] = $selectedOptions; + + if ($this->form != null) { + return $this->form->field($this->model, $this->attribute)->dropDownList($selection, $options); + } else if ($this->model != null) { + return Html::activeDropDownList($this->model, $this->attribute, $selection, $options); + } else { + $name = (!$this->name) ? 'pickerField' : $this->name; + return Html::dropDownList($name, $this->value, $selection, $options); + } + } + + /** + * Prepares the selected options either by using the $selection array or by loading the items + * by means of the model attribute value. + * + * The resulting array has the following format: + * + * [itemKey] => [ + * 'data-text' => itemText + * 'data-image' => itemImage + * 'selected' => selected + * ] + * + * Subclasses should overwrite the getItemText and getItemImage function for this purpose. + * + * @return array + */ + protected function getSelectedOptions() + { + if (!$this->selection && $this->model != null) { + $attribute = $this->attribute; + if (strrpos($attribute, '[') !== false) { + $this->selection = $this->loadItems(Html::getAttributeValue($this->model, $attribute)); + } else { + $this->selection = $this->loadItems($this->model->$attribute); + } + } + + if (!$this->selection) { + $this->selection = []; + } + + $result = []; + foreach ($this->selection as $item) { + if (!$item) { + continue; + } + + $result[$this->getItemKey($item)] = $this->buildItemOption($item); + } + return $result; + } + + /** + * Responsible for building the option data for an item. + * + * @param type $item + * @param type $selected + * @return string + */ + protected function buildItemOption($item, $selected = true) + { + $result = [ + 'data-id' => $this->getItemKey($item), + 'data-text' => $this->getItemText($item), + 'data-image' => $this->getItemImage($item), + ]; + + if ($selected) { + $result['selected'] = 'selected'; + } + + return $result; + } + + /** + * Returns the item key which is used as option value. By default we use + * the $itemKey attribibute of $item. + * + * e.g. $itemKey = 'id' + * + * @param type $item + * @return type + */ + protected function getItemKey($item) + { + $itemKey = $this->itemKey; + return $item->$itemKey; + } + + /** + * Loads all items of the given $selection array. + * The $selection array contains all selected itemKeys. + * + * @param array $selection array of itemKeys + * @return type array of items of type $itemClass or empty array for an empty selection + */ + public function loadItems($selection = null) + { + if (empty($selection)) { + return []; + } + + // For older version (prior 1.2) - try to convert comma separated list to array + if (!is_array($selection)) { + $selection = explode(',', $selection); + } + + $itemClass = $this->itemClass; + return $itemClass::find()->where([$this->itemKey => $selection])->all(); + } + + /* + * @inheritdoc + */ + protected function getAttributes() + { + return [ + 'multiple' => 'multiple', + 'size' => '1', + 'class' => 'form-control', + 'style' => 'width:100%', + 'title' => $this->placeholder + ]; + } + + /** + * Returns an array of data attributes for this picker isntance. + * Following data attributes can be configured by default: + * + * - data-placeholder: Placeholder text if no value is set. + * - data-placeholder-more: Placeholder text displayed if at least one item is set. + * - data-maximum-selected: Info message displayed if $maxSelection is exceed. + * - data-no-result: Empty result message. + * - data-format-ajax-error: Ajax error message. + * - data-load-more: Load more items text. + * - data-input-too-short: Info message displayed if $minInput characters is not exceed. + * - data-input-too-long: Info message displayed if $maxInput characters is exceed. + * + * @return array + */ + protected function getData() + { + $allowMultiple = $this->maxSelection !== 1; + + $placeholder = ($this->placeholder != null) ? $this->placeholder : Yii::t('UserModule.widgets_BasePickerField', 'Select {n,plural,=1{item} other{items}}', ['n' => ($allowMultiple) ? 2 : 1]); + $placeholderMore = ($this->placeholderMore != null) ? $this->placeholderMore : Yii::t('UserModule.widgets_BasePickerField', 'Add more...'); + + $result = [ + 'picker-url' => $this->getUrl(), + 'picker-focus' => ($this->focus) ? 'true' : null, + 'disabled-items' => (!$this->disabledItems) ? null : $this->disabledItems, + 'maximum-selection-length' => $this->maxSelection, + 'maximum-input-length' => $this->maxInput, + 'minimum-input-length' => $this->minInput, + 'placeholder' => $placeholder, + 'placeholder-more' => $placeholderMore, + 'no-result' => Yii::t('UserModule.widgets_BasePickerField', 'Your search returned no matches.'), + 'format-ajax-error' => Yii::t('UserModule.widgets_BasePickerField', 'An unexpected error occurred while loading the result.'), + 'load-more' => Yii::t('UserModule.widgets_BasePickerField', 'Load more'), + 'input-too-short' => Yii::t('UserModule.widgets_BasePickerField', 'Please enter at least {n} character', ['n' => $this->minInput]), + 'input-too-long' => Yii::t('UserModule.widgets_BasePickerField', 'You reached the maximum number of allowed charachters ({n}).', ['n' => $this->maxInput]), + 'default-results' => $this->getDefaultResultData() + ]; + + if ($this->maxSelection) { + $result['maximum-selected'] = Yii::t('UserModule.widgets_BasePickerField', 'This field only allows a maximum of {n,plural,=1{# item} other{# items}}.', ['n' => $this->maxSelection]); + } + return $result; + } + + protected function getDefaultResultData() + { + $result = []; + foreach ($this->defaultResults as $item) { + $result[] = $this->buildItemOption($item); + } + return $result; + } + + /** + * Returns the url for this picker instance. If no $url is set we use the $defaultRoute for creating the url. + * + * @return strings + */ + protected function getUrl() + { + return ($this->url) ? $this->url : Url::to([$this->defaultRoute]); + } + +} diff --git a/protected/humhub/modules/ui/form/widgets/ColorPicker.php b/protected/humhub/modules/ui/form/widgets/ColorPicker.php new file mode 100644 index 0000000000..63cf9904da --- /dev/null +++ b/protected/humhub/modules/ui/form/widgets/ColorPicker.php @@ -0,0 +1,60 @@ +field)) { + $this->attribute = $this->field; + } + } + + /** + * @inheritdoc + */ + public function run() + { + return $this->render('@ui/form/widgets/views/colorPickerField', [ + 'model' => $this->model, + 'field' => $this->attribute, + 'container' => $this->container, + 'inputId' => $this->getId(true) + ]); + } + +} diff --git a/protected/humhub/modules/ui/form/widgets/DatePicker.php b/protected/humhub/modules/ui/form/widgets/DatePicker.php new file mode 100644 index 0000000000..31174a4604 --- /dev/null +++ b/protected/humhub/modules/ui/form/widgets/DatePicker.php @@ -0,0 +1,39 @@ +dateFormat === null) { + $this->dateFormat = Yii::$app->formatter->dateInputFormat; + } + + Html::addCssClass($this->options, 'form-control'); + + parent::init(); + } + +} diff --git a/protected/humhub/modules/ui/form/widgets/DurationPicker.php b/protected/humhub/modules/ui/form/widgets/DurationPicker.php new file mode 100644 index 0000000000..d9fec82775 --- /dev/null +++ b/protected/humhub/modules/ui/form/widgets/DurationPicker.php @@ -0,0 +1,59 @@ +getView(); + $id = $this->options['id']; + + $options = [ + 'show24Hours' => true, + 'unlimitedHours' => true, + 'defaultTime' => '01:00', + 'timeSteps' => [1, 15], + 'spinnerImage' => '' + ]; + + JqueryTimeEntryAsset::register($view); + $view->registerJs("$('#{$id}').timeEntry(" . Json::htmlEncode($options) . ");"); + + Html::addCssClass($this->options, 'form-control'); + + if ($this->model !== null) { + return Html::activeTextInput($this->model, $this->attribute, $this->getOptions()); + } else { + return Html::input($this->name, $this->value, $this->getOptions()); + } + } + + public static function getDuration(\DateTime $start, \DateTime $end) + { + $duration = $start->diff($end); + return $duration->h . ':' . $duration->m; + } +} diff --git a/protected/humhub/modules/ui/form/widgets/IconPicker.php b/protected/humhub/modules/ui/form/widgets/IconPicker.php index 89550b0cdf..49036cc679 100644 --- a/protected/humhub/modules/ui/form/widgets/IconPicker.php +++ b/protected/humhub/modules/ui/form/widgets/IconPicker.php @@ -24,7 +24,6 @@ use yii\web\JsExpression; * ``` * * @since 1.3 - * @package humhub\widgets */ class IconPicker extends Select2 { diff --git a/protected/humhub/modules/ui/form/widgets/JsInputWidget.php b/protected/humhub/modules/ui/form/widgets/JsInputWidget.php new file mode 100644 index 0000000000..0f6ed8e7bd --- /dev/null +++ b/protected/humhub/modules/ui/form/widgets/JsInputWidget.php @@ -0,0 +1,113 @@ +field($model, 'from_date')->widget('WidgetClassName', [ + * // configure additional widget properties here + * ]) ?> + * ``` + * + * For more details and usage information on InputWidget, see the [guide article on forms](guide:input-forms). + * + * @see InputWidget + * @author Luke + * @since 1.3 + */ +abstract class JsInputWidget extends JsWidget +{ + /** + * If the ActiveForm is set, it should be used to create input field. + * This may differ between implementations. + * + * @var \yii\widgets\ActiveForm + */ + public $form; + + /** + * @var Model the data model that this widget is associated with. + */ + public $model; + + /** + * @var string the model attribute that this widget is associated with. + */ + public $attribute; + + /** + * @var string the input name. This must be set if [[model]] and [[attribute]] are not set. + */ + public $name; + + /** + * @var string the input value. + */ + public $value; + + /** + * @var array the HTML attributes for the input tag. + * @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered. + */ + public $options = []; + + /** + * Initializes the widget. + * If you override this method, make sure you call the parent implementation first. + * + * @throws InvalidConfigException + */ + public function init() + { + if ($this->name === null && !$this->hasModel()) { + throw new InvalidConfigException("Either 'name', or 'model' and 'attribute' properties must be specified."); + } + if (!$this->id && !isset($this->options['id'])) { + $this->id = $this->options['id'] = $this->hasModel() ? Html::getInputId($this->model, $this->attribute) : $this->getId(true); + } + parent::init(); + } + + /** + * @return string the field value either by extracting from model or if no model is given `$this->value` + * @since 1.3 + */ + protected function getValue() + { + if ($this->hasModel()) { + return Html::getAttributeValue($this->model, $this->attribute); + } + + return $this->value; + } + + /** + * @return bool whether this widget is associated with a data model. + */ + protected function hasModel() + { + return $this->model instanceof Model && $this->attribute !== null; + } + +} diff --git a/protected/humhub/modules/ui/form/widgets/Markdown.php b/protected/humhub/modules/ui/form/widgets/Markdown.php new file mode 100644 index 0000000000..d60a183138 --- /dev/null +++ b/protected/humhub/modules/ui/form/widgets/Markdown.php @@ -0,0 +1,150 @@ +previewUrl)) { + $this->previewUrl = Url::toRoute(['/markdown/preview', 'parser' => $this->parserClass]); + } + } + + public function run() + { + BootstrapMarkdownAsset::register($this->view); + $this->view->registerCssFile('@web-static/css/bootstrap-markdown-override.css'); + + if ($this->placeholder === null && $this->hasModel()) { + $this->placeholder = $this->model->getAttributeLabel($this->attribute); + } + + if ($this->form != null) { + $textArea = $this->form->field($this->model, $this->attribute)->textarea($this->getOptions())->label($this->label); + } else if ($this->model != null) { + $textArea = Html::activeTextarea($this->model, $this->attribute, $this->getOptions()); + } else { + $textArea = Html::textarea($this->name, $this->value, $this->getOptions()); + } + + return $textArea; + } + + public function getAttributes() + { + return [ + 'rows' => $this->rows, + 'disabled' => $this->disabled, + 'readonly' => $this->readonly, + 'placeholder' => $this->placeholder, + 'class' => 'form-control' + ]; + } + + public function getData() + { + if (empty($this->fileModel)) { + $this->fileModel = $this->model; + } + + if ($this->model && $this->fileAttribute) { + $this->filesInputName = $this->fileModel->formName() . '[' . $this->fileAttribute . '][]'; + } + + return [ + 'preview-url' => $this->previewUrl, + 'files-input-name' => !empty($this->filesInputName) ? $this->filesInputName : null + ]; + } +} diff --git a/protected/humhub/modules/ui/form/widgets/MarkdownModals.php b/protected/humhub/modules/ui/form/widgets/MarkdownModals.php new file mode 100644 index 0000000000..b281f91b2a --- /dev/null +++ b/protected/humhub/modules/ui/form/widgets/MarkdownModals.php @@ -0,0 +1,29 @@ +render('markdownModals'); + } + +} diff --git a/protected/humhub/modules/ui/form/widgets/MultiSelect.php b/protected/humhub/modules/ui/form/widgets/MultiSelect.php new file mode 100644 index 0000000000..34858b0a99 --- /dev/null +++ b/protected/humhub/modules/ui/form/widgets/MultiSelect.php @@ -0,0 +1,86 @@ +selection)) { + $attribute = $this->attribute; + $this->selection = ($this->model) ? $this->model->$attribute : []; + } + + if (empty($this->selection)) { + $this->selection = []; + } + + $result = []; + foreach ($this->items as $key => $value) { + if (!$value || !$key) { + continue; + } + + $result[$key] = $this->buildItemOption([$key => $value], in_array($key, $this->selection)); + } + return $result; + } + + protected function getData() + { + $result = parent::getData(); + unset($result['picker-url']); + return $result; + } + + protected function getUrl() + { + return null; + } + +} diff --git a/protected/humhub/modules/ui/form/widgets/TimePicker.php b/protected/humhub/modules/ui/form/widgets/TimePicker.php new file mode 100644 index 0000000000..eb859045b0 --- /dev/null +++ b/protected/humhub/modules/ui/form/widgets/TimePicker.php @@ -0,0 +1,35 @@ +pluginOptions['showMeridian'])) { + $this->pluginOptions['showMeridian'] = Yii::$app->formatter->isShowMeridiem(); + } + + if (!isset($this->pluginOptions['defaultTime'])) { + $this->pluginOptions['defaultTime'] = ($this->pluginOptions['showMeridian']) ? '10:00 AM' : '10:00'; + } + } +} diff --git a/protected/humhub/widgets/views/colorPickerField.php b/protected/humhub/modules/ui/form/widgets/views/colorPickerField.php similarity index 100% rename from protected/humhub/widgets/views/colorPickerField.php rename to protected/humhub/modules/ui/form/widgets/views/colorPickerField.php diff --git a/protected/humhub/modules/ui/form/widgets/views/markdownModals.php b/protected/humhub/modules/ui/form/widgets/views/markdownModals.php new file mode 100644 index 0000000000..44524c7b09 --- /dev/null +++ b/protected/humhub/modules/ui/form/widgets/views/markdownModals.php @@ -0,0 +1,55 @@ + + + + + \ No newline at end of file diff --git a/protected/humhub/widgets/ActiveField.php b/protected/humhub/widgets/ActiveField.php index 5f9db481a1..d6cacc32c1 100644 --- a/protected/humhub/widgets/ActiveField.php +++ b/protected/humhub/widgets/ActiveField.php @@ -11,27 +11,11 @@ namespace humhub\widgets; /** * A HumHub enhanced version of [[\yii\bootstrap\ActiveField]]. * + * @see \humhub\modules\ui\form\widgets\ActiveField * @since 1.2 + * @deprecated since 1.3 * @author Luke */ -class ActiveField extends \yii\bootstrap\ActiveField +class ActiveField extends \humhub\modules\ui\form\widgets\ActiveField { - - /** - * @inheritdoc - */ - public function widget($class, $config = []) - { - /* @var $class \yii\base\Widget */ - $config['model'] = $this->model; - $config['attribute'] = $this->attribute; - $config['view'] = $this->form->getView(); - - if (isset($config['options']) && isset(class_parents($class)['humhub\widgets\InputWidget'])) { - $this->adjustLabelFor($config['options']); - } - - return parent::widget($class, $config); - } - } diff --git a/protected/humhub/widgets/ActiveForm.php b/protected/humhub/widgets/ActiveForm.php index 0d798eb905..deb2e2016b 100644 --- a/protected/humhub/widgets/ActiveForm.php +++ b/protected/humhub/widgets/ActiveForm.php @@ -11,20 +11,11 @@ namespace humhub\widgets; /** * ActiveForm * + * @see \humhub\modules\ui\form\widgets\ActiveForm + * @deprecated since 1.3 * @since 1.1 * @author Luke */ -class ActiveForm extends \yii\bootstrap\ActiveForm +class ActiveForm extends \humhub\modules\ui\form\widgets\ActiveForm { - - /** - * @inheritdoc - */ - public $enableClientValidation = false; - - /** - * @inheritdoc - */ - public $fieldClass = 'humhub\widgets\ActiveField'; - } diff --git a/protected/humhub/widgets/BasePickerField.php b/protected/humhub/widgets/BasePickerField.php index 96e883e442..f56e958c0c 100644 --- a/protected/humhub/widgets/BasePickerField.php +++ b/protected/humhub/widgets/BasePickerField.php @@ -2,404 +2,12 @@ namespace humhub\widgets; -use Yii; -use yii\helpers\Html; -use \yii\helpers\Url; - /** - * Abstract class for picker form fields. - * - * Subclasses should at least overwrite the following fields: - * - * - $defaultRoute for defining a default search query route - * - $itemClass defines the type of item e.g. User/Space/... - * - $itemKey defines the key attribute used as option values e.g. id/guid - * - * And the following methods: - * - * - getItemText for retrieving the option text for an item - * - getItemImage for retrieving the option image (if required) - * - * - * The json result of a picker search query should return an array of items with the following key/values: - * - * - id: option value (itemKey) (required) - * - text: option text (required) - * - image: option image (optional) - * - priority: used to sort results (optional) - * - disabled: can be used to disable certain items (optional) - * - disabbledText: text describing the reason why the item is disabled (optional) - * - * @package humhub.modules_core.user.widgets + * @deprecated since 1.3 * @since 1.2 * @author buddha */ -abstract class BasePickerField extends InputWidget +abstract class BasePickerField extends \humhub\modules\ui\form\widgets\BasePicker { - /** - * Defines the javascript picker implementation. - * - * @var string - */ - public $jsWidget = 'ui.picker.Picker'; - - /** - * Disabled items - */ - public $disabledItems; - - /** - * Default route used for search queries. - * This can be overwritten by defining the $url. - * - * @var string - */ - public $defaultRoute; - - /** - * Search url used to overwrite the $defaultRoute for a picker isntance. - * - * @var string - */ - public $url; - - /** - * Maximum amount of selection items. - * - * @var integer - */ - public $maxSelection = 50; - - /** - * Minimum character input before triggering search query. - * - * @var integer - */ - public $minInput = 3; - - /** - * Minimum character input before triggering search query. - * - * @var integer - */ - public $maxInput = 20; - - /** - * Array of item instances. If this array is set the picker will ignore the - * actual model attribute and instead use this array as selection. - * - * It this array is not set, the picker will try to load the items by means of the - * model attribute - * - * @see BasePickerField::loadItems - * @var array - */ - public $selection; - - /** - * @var array Array of item instances used as long the minInput is not exceed. - */ - public $defaultResults = []; - - /** - * The item class used to load items by means of the model attribute value. - * - * @var string - */ - public $itemClass; - - /** - * The item key used as option value and loading items by attribute value. - * e.g. id or guid - * - * @var string - */ - public $itemKey; - - /** - * If the ActiveForm is set, it will be used to create the picker field, - * otherwise it's created by Html::activeDropDownList - * - * @var \yii\widgets\ActiveForm - */ - public $form; - - /** - * @deprecated since 1.2.2 use $name instead - */ - public $formName; - - /** - * Model instance. - * - * @var \yii\db\ActiveRecord - */ - public $model; - - /** - * Model attribute which holds the picker value. The referenced model attribute has to be an - * array. - * - * @var string - */ - public $attribute; - - - /** - * Can be used to overwrite the default placeholder. - * @var string - */ - public $placeholder; - - /** - * Can be used to overwrite the default add more placeholder. - * @var string - */ - public $placeholderMore; - - /** - * If set to true the picker will be focused automatically. - * - * @var boolean - */ - public $focus = false; - - /** - * @inheritdoc - * @var boolean - */ - public $init = true; - - /** - * Used to retrieve the option text of a given $item. - * - * @param \yii\db\ActiveRecord $item selected item - * @return string item option text - */ - protected abstract function getItemText($item); - - /** - * Used to retrieve the option image url of a given $item. - * - * @param \yii\db\ActiveRecord $item selected item - * @return string image url or null if no selection image required. - */ - protected abstract function getItemImage($item); - - /** - * @inhertidoc - */ - public function run() - { - \humhub\assets\Select2BootstrapAsset::register($this->view); - - //Only for compatibility - if(empty($this->name)) { - $this->name = $this->formName; - } - - if ($this->selection != null && !is_array($this->selection)) { - $this->selection = [$this->selection]; - } - - // Prepare current selection and selection options - $selection = []; - $selectedOptions = $this->getSelectedOptions(); - foreach ($selectedOptions as $id => $option) { - $selection[$id] = $option['data-text']; - } - - $options = $this->getOptions(); - $options['options'] = $selectedOptions; - - if ($this->form != null) { - return $this->form->field($this->model, $this->attribute)->dropDownList($selection, $options); - } else if ($this->model != null) { - return Html::activeDropDownList($this->model, $this->attribute, $selection, $options); - } else { - $name = (!$this->name) ? 'pickerField' : $this->name; - return Html::dropDownList($name, $this->value, $selection, $options); - } - } - - /** - * Prepares the selected options either by using the $selection array or by loading the items - * by means of the model attribute value. - * - * The resulting array has the following format: - * - * [itemKey] => [ - * 'data-text' => itemText - * 'data-image' => itemImage - * 'selected' => selected - * ] - * - * Subclasses should overwrite the getItemText and getItemImage function for this purpose. - * - * @return array - */ - protected function getSelectedOptions() - { - if (!$this->selection && $this->model != null) { - $attribute = $this->attribute; - if(strrpos($attribute, '[') !== false) { - $this->selection = $this->loadItems(Html::getAttributeValue($this->model, $attribute)); - } else { - $this->selection = $this->loadItems($this->model->$attribute); - } - } - - if (!$this->selection) { - $this->selection = []; - } - - $result = []; - foreach ($this->selection as $item) { - if (!$item) { - continue; - } - - $result[$this->getItemKey($item)] = $this->buildItemOption($item); - } - return $result; - } - - /** - * Responsible for building the option data for an item. - * - * @param type $item - * @param type $selected - * @return string - */ - protected function buildItemOption($item, $selected = true) - { - $result = [ - 'data-id' => $this->getItemKey($item), - 'data-text' => $this->getItemText($item), - 'data-image' => $this->getItemImage($item), - ]; - - if ($selected) { - $result['selected'] = 'selected'; - } - - return $result; - } - - /** - * Returns the item key which is used as option value. By default we use - * the $itemKey attribibute of $item. - * - * e.g. $itemKey = 'id' - * - * @param type $item - * @return type - */ - protected function getItemKey($item) - { - $itemKey = $this->itemKey; - return $item->$itemKey; - } - - /** - * Loads all items of the given $selection array. - * The $selection array contains all selected itemKeys. - * - * @param array $selection array of itemKeys - * @return type array of items of type $itemClass or empty array for an empty selection - */ - public function loadItems($selection = null) - { - if (empty($selection)) { - return []; - } - - // For older version (prior 1.2) - try to convert comma separated list to array - if (!is_array($selection)) { - $selection = explode(',', $selection); - } - - $itemClass = $this->itemClass; - return $itemClass::find()->where([$this->itemKey => $selection])->all(); - } - - /* - * @inheritdoc - */ - protected function getAttributes() - { - return [ - 'multiple' => 'multiple', - 'size' => '1', - 'class' => 'form-control', - 'style' => 'width:100%', - 'title' => $this->placeholder - ]; - } - - /** - * Returns an array of data attributes for this picker isntance. - * Following data attributes can be configured by default: - * - * - data-placeholder: Placeholder text if no value is set. - * - data-placeholder-more: Placeholder text displayed if at least one item is set. - * - data-maximum-selected: Info message displayed if $maxSelection is exceed. - * - data-no-result: Empty result message. - * - data-format-ajax-error: Ajax error message. - * - data-load-more: Load more items text. - * - data-input-too-short: Info message displayed if $minInput characters is not exceed. - * - data-input-too-long: Info message displayed if $maxInput characters is exceed. - * - * @return array - */ - protected function getData() - { - $allowMultiple = $this->maxSelection !== 1; - - $placeholder = ($this->placeholder != null) ? $this->placeholder : Yii::t('UserModule.widgets_BasePickerField', 'Select {n,plural,=1{item} other{items}}', ['n' => ($allowMultiple) ? 2 : 1]); - $placeholderMore = ($this->placeholderMore != null) ? $this->placeholderMore : Yii::t('UserModule.widgets_BasePickerField', 'Add more...'); - - $result = [ - 'picker-url' => $this->getUrl(), - 'picker-focus' => ($this->focus) ? 'true' : null, - 'disabled-items' => (!$this->disabledItems) ? null : $this->disabledItems, - 'maximum-selection-length' => $this->maxSelection, - 'maximum-input-length' => $this->maxInput, - 'minimum-input-length' => $this->minInput, - 'placeholder' => $placeholder, - 'placeholder-more' => $placeholderMore, - 'no-result' => Yii::t('UserModule.widgets_BasePickerField', 'Your search returned no matches.'), - 'format-ajax-error' => Yii::t('UserModule.widgets_BasePickerField', 'An unexpected error occurred while loading the result.'), - 'load-more' => Yii::t('UserModule.widgets_BasePickerField', 'Load more'), - 'input-too-short' => Yii::t('UserModule.widgets_BasePickerField', 'Please enter at least {n} character', ['n' => $this->minInput]), - 'input-too-long' => Yii::t('UserModule.widgets_BasePickerField', 'You reached the maximum number of allowed charachters ({n}).', ['n' => $this->maxInput]), - 'default-results' => $this->getDefaultResultData() - ]; - - if ($this->maxSelection) { - $result['maximum-selected'] = Yii::t('UserModule.widgets_BasePickerField', 'This field only allows a maximum of {n,plural,=1{# item} other{# items}}.', ['n' => $this->maxSelection]); - } - return $result; - } - - protected function getDefaultResultData() - { - $result = []; - foreach ($this->defaultResults as $item) { - $result[] = $this->buildItemOption($item); - } - return $result; - } - - /** - * Returns the url for this picker instance. If no $url is set we use the $defaultRoute for creating the url. - * - * @return strings - */ - protected function getUrl() - { - return ($this->url) ? $this->url : Url::to([$this->defaultRoute]); - } - } diff --git a/protected/humhub/widgets/ColorPickerField.php b/protected/humhub/widgets/ColorPickerField.php index b07d32e8e3..c1b360fecb 100644 --- a/protected/humhub/widgets/ColorPickerField.php +++ b/protected/humhub/widgets/ColorPickerField.php @@ -8,45 +8,17 @@ namespace humhub\widgets; +use humhub\modules\ui\form\widgets\ColorPicker; + /** * Adds a color picker form field for the given model. * + * @see ColorPicker + * @deprecated since 1.3 * @author buddha */ -class ColorPickerField extends InputWidget +class ColorPickerField extends ColorPicker { - /** - * @deprecated since v1.2.2 use $attribute instead - */ - public $field; - - /** - * The container id used to append the actual color picker js widget. - * @var string - */ - public $container; - - /** - * @inheritdoc - */ - public $attribute = 'color'; - - public function init() - { - if(!empty($this->field)) { - $this->attribute = $this->field; - } - } - - public function run() - { - return $this->render('colorPickerField', [ - 'model' => $this->model, - 'field' => $this->attribute, - 'container' => $this->container, - 'inputId' => $this->getId(true) - ]); - } } diff --git a/protected/humhub/widgets/ContentTagDropDown.php b/protected/humhub/widgets/ContentTagDropDown.php index 07a053e5be..064915f635 100644 --- a/protected/humhub/widgets/ContentTagDropDown.php +++ b/protected/humhub/widgets/ContentTagDropDown.php @@ -8,102 +8,14 @@ namespace humhub\widgets; -use humhub\libs\Html; -use humhub\modules\content\models\ContentTag; -class ContentTagDropDown extends InputWidget +/** + * Class ContentTagDropDown + * + * @see \humhub\modules\content\widgets\ContentTagDropDown + * @deprecated since 1.3 + * @package humhub\widgets + */ +class ContentTagDropDown extends \humhub\modules\content\widgets\ContentTagDropDown { - /** - * @var string tagClass - */ - public $tagClass; - public $query; - public $contentContainer; - public $includeGlobal = false; - public $type = true; - public $prompt = false; - public $promptValue = 0; - - public $items; - private $itemOptions = []; - - public function int() - { - if (!$this->tagClass) { - $this->tagClass = ContentTag::class; - // Reset default behavior inf no specific tagClass is given - if ($this->type === true) { - $this->type = null; - } - } - - if (!$this->none && !$this->noneLabel) { - $this->noneLabel = Yii::t('ContentModule.widgets_ContentTagDropDown', 'None'); - } - } - - public function run() - { - $items = $this->getItems(); - - if (empty($items)) { - return; - } - - $options = $this->getOptions(); - unset($options['id']); - - if ($this->form && $this->hasModel()) { - return $this->form->field($this->model, $this->attribute)->dropDownList($items, $options); - } elseif ($this->hasModel()) { - return Html::activeDropDownList($this->model, $this->attribute, $items, $options); - } else { - return Html::dropDownList($this->name, $this->value, $items, $options); - } - } - - public function getAttributes() - { - $result = [ - 'class' => 'form-control', - 'options' => $this->itemOptions - ]; - - if ($this->prompt) { - $result['prompt'] = $this->prompt; - } - - return $result; - } - - public function getItems() - { - if ($this->items) { - return $this->items; - } - - if (!$this->query) { - if ($this->contentContainer) { - $this->query = call_user_func($this->tagClass .'::findByContainer', $this->contentContainer, $this->includeGlobal); - } elseif (!empty($this->type)) { - $type = ($this->type === true) ? $this->tagClass : $this->type; - $this->query = call_user_func($this->tagClass .'::findByType', [$type]); - } else { - $this->query = call_user_func($this->tagClass .'::find'); - } - } - - $tags = $this->items = $this->query->all(); - - $result = []; - foreach ($tags as $tag) { - $result[$tag->id] = $tag->name; - $this->itemOptions[$tag->id] = [ - 'data-type-color' => $tag->color - ]; - } - - return $result; - } - } diff --git a/protected/humhub/widgets/DatePicker.php b/protected/humhub/widgets/DatePicker.php index f3638ba06d..7f6e16a536 100644 --- a/protected/humhub/widgets/DatePicker.php +++ b/protected/humhub/widgets/DatePicker.php @@ -8,31 +8,15 @@ namespace humhub\widgets; -use Yii; -use yii\jui\DatePicker as BaseDatePicker; -use humhub\libs\Html; /** * DatePicker * - * @since 1.2.3 - * @author Luke + * @see \humhub\modules\ui\form\widgets\DatePicker + * @deprecated since 1.3 + * @package humhub\widgets */ -class DatePicker extends BaseDatePicker +class DatePicker extends \humhub\modules\ui\form\widgets\DatePicker { - /** - * @inheritdoc - */ - public function init() - { - if ($this->dateFormat === null) { - $this->dateFormat = Yii::$app->formatter->dateInputFormat; - } - - Html::addCssClass($this->options, 'form-control'); - - parent::init(); - } - } diff --git a/protected/humhub/widgets/DurationPicker.php b/protected/humhub/widgets/DurationPicker.php index c2cbb4d145..54ad21d09b 100644 --- a/protected/humhub/widgets/DurationPicker.php +++ b/protected/humhub/widgets/DurationPicker.php @@ -8,52 +8,13 @@ namespace humhub\widgets; -use Yii; -use humhub\libs\Html; -use yii\helpers\Json; -use humhub\assets\JqueryTimeEntryAsset; -use humhub\widgets\InputWidget; - /** * DurationPicker renders an UI form widget to select time durations. * - * @since 1.2.3 + * @see \humhub\modules\ui\form\widgets\DurationPicker + * @deprecated since 1.3 * @author Luke */ -class DurationPicker extends InputWidget +class DurationPicker extends \humhub\modules\ui\form\widgets\DurationPicker { - - /** - * @inheritdoc - */ - public function run() - { - $view = $this->getView(); - $id = $this->options['id']; - - $options = [ - 'show24Hours' => true, - 'unlimitedHours' => true, - 'defaultTime' => '01:00', - 'timeSteps' => [1, 15], - 'spinnerImage' => '' - ]; - - JqueryTimeEntryAsset::register($view); - $view->registerJs("$('#{$id}').timeEntry(" . Json::htmlEncode($options) . ");"); - - Html::addCssClass($this->options, 'form-control'); - - if ($this->model !== null) { - return Html::activeTextInput($this->model, $this->attribute, $this->getOptions()); - } else { - return Html::input($this->name, $this->value, $this->getOptions()); - } - } - - public static function getDuration(\DateTime $start, \DateTime $end) - { - $duration = $start->diff($end); - return $duration->h . ':' . $duration->m; - } } diff --git a/protected/humhub/widgets/InputWidget.php b/protected/humhub/widgets/InputWidget.php index da2ef47162..46bd3c80b3 100644 --- a/protected/humhub/widgets/InputWidget.php +++ b/protected/humhub/widgets/InputWidget.php @@ -8,102 +8,14 @@ namespace humhub\widgets; -use humhub\widgets\JsWidget; -use yii\base\Model; -use yii\base\InvalidConfigException; -use yii\helpers\Html; +use humhub\modules\ui\form\widgets\JsInputWidget; /** - * InputWidget is the base class for widgets that collect user inputs. - * - * An input widget can be associated with a data model and an attribute, - * or a name and a value. If the former, the name and the value will - * be generated automatically. - * - * Classes extending from this widget can be used in an [[\yii\widgets\ActiveForm|ActiveForm]] - * using the [[\yii\widgets\ActiveField::widget()|widget()]] method, for example like this: - * - * ```php - * field($model, 'from_date')->widget('WidgetClassName', [ - * // configure additional widget properties here - * ]) ?> - * ``` - * - * For more details and usage information on InputWidget, see the [guide article on forms](guide:input-forms). - * + * @see JsInputWidget + * @deprecated since 1.3 * @author Luke * @since 2.0 */ -class InputWidget extends JsWidget +class InputWidget extends JsInputWidget { - /** - * If the ActiveForm is set, it should be used to create input field. - * This may differ between implementations. - * - * @var \yii\widgets\ActiveForm - */ - public $form; - - /** - * @var Model the data model that this widget is associated with. - */ - public $model; - - /** - * @var string the model attribute that this widget is associated with. - */ - public $attribute; - - /** - * @var string the input name. This must be set if [[model]] and [[attribute]] are not set. - */ - public $name; - - /** - * @var string the input value. - */ - public $value; - - /** - * @var array the HTML attributes for the input tag. - * @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered. - */ - public $options = []; - - /** - * Initializes the widget. - * If you override this method, make sure you call the parent implementation first. - */ - public function init() - { - if ($this->name === null && !$this->hasModel()) { - throw new InvalidConfigException("Either 'name', or 'model' and 'attribute' properties must be specified."); - } - if (!$this->id && !isset($this->options['id'])) { - $this->id = $this->options['id'] = $this->hasModel() ? Html::getInputId($this->model, $this->attribute) : $this->getId(true); - } - parent::init(); - } - - /** - * @return string the field value either by extracting from model or if no model is given `$this->value` - * @since 1.3 - */ - protected function getValue() - { - if($this->hasModel()) { - return Html::getAttributeValue($this->model, $this->attribute); - } - - return $this->value; - } - - /** - * @return bool whether this widget is associated with a data model. - */ - protected function hasModel() - { - return $this->model instanceof Model && $this->attribute !== null; - } - } diff --git a/protected/humhub/widgets/LayoutAddons.php b/protected/humhub/widgets/LayoutAddons.php index 1eb927f86f..85fc813e9e 100644 --- a/protected/humhub/widgets/LayoutAddons.php +++ b/protected/humhub/widgets/LayoutAddons.php @@ -8,6 +8,7 @@ namespace humhub\widgets; +use humhub\modules\ui\form\widgets\MarkdownModals; use Yii; /** @@ -36,7 +37,7 @@ class LayoutAddons extends BaseStack $this->addWidget(LoaderWidget::class, ['show' => false, 'id' => "humhub-ui-loader-default"]); $this->addWidget(StatusBar::class); $this->addWidget(BlueimpGallery::class); - $this->addWidget(MarkdownFieldModals::class); + $this->addWidget(MarkdownModals::class); if (Yii::$app->params['enablePjax']) { $this->addWidget(Pjax::class); diff --git a/protected/humhub/widgets/MarkdownField.php b/protected/humhub/widgets/MarkdownField.php index fa9298061e..80307dd251 100644 --- a/protected/humhub/widgets/MarkdownField.php +++ b/protected/humhub/widgets/MarkdownField.php @@ -6,150 +6,18 @@ * */ -/** - * Created by PhpStorm. - * User: buddha - * Date: 18.07.2017 - * Time: 14:27 - */ - namespace humhub\widgets; -use humhub\assets\BootstrapMarkdownAsset; -use humhub\libs\Html; -use humhub\modules\file\widgets\UploadButton; -use yii\helpers\Url; + +use humhub\modules\ui\form\widgets\Markdown; /** * Simple Markdown Editor form fields. * + * @see Markdown + * @deprecated since 1.3 * @package humhub\widgets * @since 1.2.2 */ -class MarkdownField extends InputWidget +class MarkdownField extends Markdown { - /** - * @inheritdoc - */ - public $jsWidget = 'ui.markdown.MarkdownField'; - - /** - * @var int defines the HTML rows attribute of the textarea - */ - public $rows = 3; - - /** - * @var string markdown preview url - */ - public $previewUrl; - - /** - * HMarkdown parser class used for preview - * - * @var string - */ - public $parserClass = "HMarkdown"; - - /** - * @var bool show label - */ - public $label = false; - - /** - * @var string defines the name of the hidden input name for uploaded files if not set the UploadButton default is used - * @see UploadButton - */ - public $filesInputName; - - /** - * Can defined in addition to $fileAttribute to change the form model of the file from $model to $fileModel. - * Note: this is only affects the formName for the file upload. - * @var string - */ - public $fileModel; - - /** - * Can be set if $model is defined, to create a loadable fileInput name which is respected in Model::load() - * Note: this is only affects the formName for the file upload. - * @var string - */ - public $fileAttribute; - - /** - * @var boolean if set to true the markdown field will be disabled - */ - public $disabled = false; - - /** - * @var boolean if set to true the markdown field will set to readonly - */ - public $readonly = false; - - /** - * @var string - */ - public $placeholder; - - /** - * @inheritdoc - */ - public $fadeIn = 'fast'; - - /** - * @inheritdoc - */ - public $init = true; - - public function init() - { - if (empty($this->previewUrl)) { - $this->previewUrl = Url::toRoute(['/markdown/preview', 'parser' => $this->parserClass]); - } - } - - public function run() - { - BootstrapMarkdownAsset::register($this->view); - $this->view->registerCssFile('@web-static/css/bootstrap-markdown-override.css'); - - if($this->placeholder === null && $this->hasModel()) { - $this->placeholder = $this->model->getAttributeLabel($this->attribute); - } - - if ($this->form != null) { - $textArea = $this->form->field($this->model, $this->attribute)->textarea($this->getOptions())->label($this->label); - } else if ($this->model != null) { - $textArea = Html::activeTextarea($this->model, $this->attribute, $this->getOptions()); - } else { - $textArea = Html::textarea($this->name, $this->value, $this->getOptions()); - } - - return $textArea; - } - - public function getAttributes() - { - return [ - 'rows' => $this->rows, - 'disabled' => $this->disabled, - 'readonly' => $this->readonly, - 'placeholder' => $this->placeholder, - 'class' => 'form-control' - ]; - } - - public function getData() - { - if(empty($this->fileModel)) { - $this->fileModel = $this->model; - } - - if($this->model && $this->fileAttribute) { - $this->filesInputName = $this->fileModel->formName().'['.$this->fileAttribute.'][]'; - } - - return [ - 'preview-url' => $this->previewUrl, - 'files-input-name' => !empty($this->filesInputName) ? $this->filesInputName : null - ]; - } -} \ No newline at end of file +} diff --git a/protected/humhub/widgets/MarkdownFieldModals.php b/protected/humhub/widgets/MarkdownFieldModals.php index d718a3ac5f..b753c218f1 100644 --- a/protected/humhub/widgets/MarkdownFieldModals.php +++ b/protected/humhub/widgets/MarkdownFieldModals.php @@ -1,4 +1,5 @@ render('markdownFieldModals'); - } -} \ No newline at end of file +} diff --git a/protected/humhub/widgets/MultiSelectField.php b/protected/humhub/widgets/MultiSelectField.php index e681c5d1e6..10a643004a 100644 --- a/protected/humhub/widgets/MultiSelectField.php +++ b/protected/humhub/widgets/MultiSelectField.php @@ -2,78 +2,14 @@ namespace humhub\widgets; +use humhub\modules\ui\form\widgets\MultiSelect; + /** - * @package humhub.modules_core.user.widgets + * @see MultiSelect + * @deprecated since 1.3 * @since 1.2 * @author buddha */ -class MultiSelectField extends BasePickerField +class MultiSelectField extends MultiSelect { - - /** - * @inerhitdoc - */ - public $minInput = 0; - - /** - * Possible values - * @var type - */ - public $items = []; - - /** - * @inheritdoc - */ - protected function getItemText($item) - { - return array_values($item)[0]; - } - - /** - * @inheritdoc - */ - protected function getItemImage($item) - { - return null; - } - - protected function getItemKey($item) - { - return key($item); - } - - protected function getSelectedOptions() - { - if(empty($this->selection)) { - $attribute = $this->attribute; - $this->selection = ($this->model) ? $this->model->$attribute : []; - } - - if(empty($this->selection)) { - $this->selection = []; - } - - $result = []; - foreach ($this->items as $key => $value) { - if (!$value || !$key) { - continue; - } - - $result[$key] = $this->buildItemOption([$key => $value], in_array($key, $this->selection)); - } - return $result; - } - - protected function getData() - { - $result = parent::getData(); - unset($result['picker-url']); - return $result; - } - - protected function getUrl() - { - return null; - } - } diff --git a/protected/humhub/widgets/TimePicker.php b/protected/humhub/widgets/TimePicker.php index 4a7bc40e05..7f65dc3641 100644 --- a/protected/humhub/widgets/TimePicker.php +++ b/protected/humhub/widgets/TimePicker.php @@ -7,22 +7,16 @@ namespace humhub\widgets; -use kartik\base\TranslationTrait; -use kartik\base\WidgetTrait; use Yii; -class TimePicker extends \kartik\time\TimePicker +/** + * Class TimePicker + * + * @see \humhub\modules\ui\form\widgets\TimePicker + * @deprecated since 1.3 + * @package humhub\widgets + */ +class TimePicker extends \humhub\modules\ui\form\widgets\TimePicker { - public function init() - { - parent::init(); - if (!isset($this->pluginOptions['showMeridian'])) { - $this->pluginOptions['showMeridian'] = Yii::$app->formatter->isShowMeridiem(); - } - - if (!isset($this->pluginOptions['defaultTime'])) { - $this->pluginOptions['defaultTime'] = ($this->pluginOptions['showMeridian']) ? '10:00 AM' : '10:00'; - } - } }