diff --git a/README.md b/README.md index f39113c..a276f4c 100755 --- a/README.md +++ b/README.md @@ -73,7 +73,7 @@ The following widgets are currently available: * Breadcrumbs * Button * Carousel -* Chip +* ChipInput * Collapsible * DatePicker * DetailView @@ -93,6 +93,7 @@ The following widgets are currently available: * SideNav * Slider * Spinner +* StaticChip * SubmitButton * SwitchButton * TimePicker diff --git a/composer.json b/composer.json index 690733c..8264a6d 100755 --- a/composer.json +++ b/composer.json @@ -15,10 +15,10 @@ ], "version": "3.0.0", "require": { - "php": ">=7.0.0", - "yiisoft/yii2": "~2.0.14", + "php": ">=5.6.0", + "yiisoft/yii2": "~2.0.0", - "bower-asset/materialize": "1.0.0-beta" + "bower-asset/materialize": "1.0.*@beta" }, "autoload": { "psr-4": { diff --git a/src/assets/MaterializeAsset.php b/src/assets/MaterializeAsset.php index 1f95440..942653a 100755 --- a/src/assets/MaterializeAsset.php +++ b/src/assets/MaterializeAsset.php @@ -11,7 +11,7 @@ /** * MaterializeAsset provides the required Materialize CSS files. - * + * * @author Christoph Erdmann * @package assets */ @@ -33,6 +33,6 @@ class MaterializeAsset extends AssetBundle * @var array list of bundle class names that this bundle depends on. */ public $depends = [ - 'macgyer\yii2materializecss\assets\MaterializeFontAsset', + MaterializeFontAsset::class, ]; } diff --git a/src/assets/MaterializePluginAsset.php b/src/assets/MaterializePluginAsset.php index 87c65c5..ef58546 100755 --- a/src/assets/MaterializePluginAsset.php +++ b/src/assets/MaterializePluginAsset.php @@ -11,7 +11,7 @@ /** * MaterializePluginAsset provides the Materialize JS files. - * + * * @author Christoph Erdmann * @package assets */ @@ -21,18 +21,11 @@ class MaterializePluginAsset extends AssetBundle * @var string the directory that contains the source asset files for this asset bundle. */ public $sourcePath = '@bower/materialize/dist'; - + /** * @var array list of JS files that this bundle contains. */ public $js = [ 'js/materialize.min.js' ]; - - /** - * @var array list of bundle class names that this bundle depends on. - */ - public $depends = [ - 'yii\web\JqueryAsset' - ]; } diff --git a/src/lib/Html.php b/src/lib/Html.php index a01e1f3..2a7dfd5 100755 --- a/src/lib/Html.php +++ b/src/lib/Html.php @@ -133,4 +133,410 @@ private static function normalizeMaxLength($model, $attribute, &$options) } } } + + /** + * Generates a radio button tag together with a label for the given model attribute. + * This method will generate the "checked" tag attribute according to the model attribute value. + * @param Model $model the model object + * @param string $attribute the attribute name or expression. See [\yii\helpers\Html::getAttributeName()](https://www.yiiframework.com/doc/api/2.0/yii-helpers-basehtml#getInputName()-detail) for the format + * about attribute expression. + * @param array $options the tag options in terms of name-value pairs. + * See [[booleanInput()]] for details about accepted attributes. + * + * @return string the generated radio button tag + */ + public static function activeRadio($model, $attribute, $options = []) + { + return static::activeBooleanInput('radio', $model, $attribute, $options); + } + + /** + * Generates a checkbox tag together with a label for the given model attribute. + * This method will generate the "checked" tag attribute according to the model attribute value. + * @param Model $model the model object + * @param string $attribute the attribute name or expression. See [\yii\helpers\Html::getAttributeName()](https://www.yiiframework.com/doc/api/2.0/yii-helpers-basehtml#getInputName()-detail) for the format + * about attribute expression. + * @param array $options the tag options in terms of name-value pairs. + * See [[booleanInput()]] for details about accepted attributes. + * + * @return string the generated checkbox tag + */ + public static function activeCheckbox($model, $attribute, $options = []) + { + return static::activeBooleanInput('checkbox', $model, $attribute, $options); + } + + /** + * Generates a boolean input + * This method is mainly called by [[activeCheckbox()]] and [[activeRadio()]]. + * @param string $type the input type. This can be either `radio` or `checkbox`. + * @param Model $model the model object + * @param string $attribute the attribute name or expression. See [\yii\helpers\Html::getAttributeName()](https://www.yiiframework.com/doc/api/2.0/yii-helpers-basehtml#getInputName()-detail) for the format + * about attribute expression. + * @param array $options the tag options in terms of name-value pairs. + * See [[booleanInput()]] for details about accepted attributes. + * @return string the generated input element + * @since 2.0.9 + */ + protected static function activeBooleanInput($type, $model, $attribute, $options = []) + { + $name = isset($options['name']) ? $options['name'] : static::getInputName($model, $attribute); + $value = static::getAttributeValue($model, $attribute); + + if (!array_key_exists('value', $options)) { + $options['value'] = '1'; + } + if (!array_key_exists('uncheck', $options)) { + $options['uncheck'] = '0'; + } elseif ($options['uncheck'] === false) { + unset($options['uncheck']); + } + if (!array_key_exists('label', $options)) { + $options['label'] = static::encode($model->getAttributeLabel(static::getAttributeName($attribute))); + } elseif ($options['label'] === false) { + unset($options['label']); + } + + if (isset($options['label'])) { + $options['label'] = '' . $options['label'] . ''; + } + + $checked = "$value" === "{$options['value']}"; + + if (!array_key_exists('id', $options)) { + $options['id'] = static::getInputId($model, $attribute); + } + + return static::$type($name, $checked, $options); + } + + /** + * Generates a list of checkboxes. A checkbox list allows multiple selection. + * As a result, the corresponding submitted value is an array. + * The selection of the checkbox list is taken from the value of the model attribute. + * @param Model $model the model object + * @param string $attribute the attribute name or expression. See [\yii\helpers\Html::getAttributeName()](https://www.yiiframework.com/doc/api/2.0/yii-helpers-basehtml#getInputName()-detail) for the format + * about attribute expression. + * @param array $items the data item used to generate the checkboxes. + * The array keys are the checkbox values, and the array values are the corresponding labels. + * Note that the labels will NOT be HTML-encoded, while the values will. + * @param array $options options (name => config) for the checkbox list container tag. + * The following options are specially handled: + * + * - tag: string|false, the tag name of the container element. False to render checkbox without container. + * See also [\yii\helpers\Html::tag()](https://www.yiiframework.com/doc/api/2.0/yii-helpers-basehtml#tag()-detail). + * - unselect: string, the value that should be submitted when none of the checkboxes is selected. + * You may set this option to be null to prevent default value submission. + * If this option is not set, an empty string will be submitted. + * - encode: boolean, whether to HTML-encode the checkbox labels. Defaults to true. + * This option is ignored if `item` option is set. + * - separator: string, the HTML code that separates items. + * - itemOptions: array, the options for generating the checkbox tag using [\yii\helpers\Html::checkbox()](https://www.yiiframework.com/doc/api/2.0/yii-helpers-basehtml#checkbox()-detail). + * - item: callable, a callback that can be used to customize the generation of the HTML code + * corresponding to a single item in $items. The signature of this callback must be: + * + * ```php + * function ($index, $label, $name, $checked, $value) + * ``` + * + * where $index is the zero-based index of the checkbox in the whole list; $label + * is the label for the checkbox; and $name, $value and $checked represent the name, + * value and the checked status of the checkbox input. + * + * See [\yii\helpers\Html::renderTagAttributes()](https://www.yiiframework.com/doc/api/2.0/yii-helpers-basehtml#renderTagAttributes()-detail) for details on how attributes are being rendered. + * + * @return string the generated checkbox list + */ + public static function activeCheckboxList($model, $attribute, $items, $options = []) + { + return static::activeListInput('checkboxList', $model, $attribute, $items, $options); + } + + /** + * Generates a list of radio buttons. + * A radio button list is like a checkbox list, except that it only allows single selection. + * The selection of the radio buttons is taken from the value of the model attribute. + * @param Model $model the model object + * @param string $attribute the attribute name or expression. See [\yii\helpers\Html::getAttributeName()](https://www.yiiframework.com/doc/api/2.0/yii-helpers-basehtml#getInputName()-detail) for the format + * about attribute expression. + * @param array $items the data item used to generate the radio buttons. + * The array keys are the radio values, and the array values are the corresponding labels. + * Note that the labels will NOT be HTML-encoded, while the values will. + * @param array $options options (name => config) for the radio button list container tag. + * The following options are specially handled: + * + * - tag: string|false, the tag name of the container element. False to render radio button without container. + * See also [\yii\helpers\Html::tag()](https://www.yiiframework.com/doc/api/2.0/yii-helpers-basehtml#tag()-detail). + * - unselect: string, the value that should be submitted when none of the radio buttons is selected. + * You may set this option to be null to prevent default value submission. + * If this option is not set, an empty string will be submitted. + * - encode: boolean, whether to HTML-encode the checkbox labels. Defaults to true. + * This option is ignored if `item` option is set. + * - separator: string, the HTML code that separates items. + * - itemOptions: array, the options for generating the radio button tag using [[radio()]]. + * - item: callable, a callback that can be used to customize the generation of the HTML code + * corresponding to a single item in $items. The signature of this callback must be: + * + * ```php + * function ($index, $label, $name, $checked, $value) + * ``` + * + * where $index is the zero-based index of the radio button in the whole list; $label + * is the label for the radio button; and $name, $value and $checked represent the name, + * value and the checked status of the radio button input. + * + * See [\yii\helpers\Html::renderTagAttributes()](https://www.yiiframework.com/doc/api/2.0/yii-helpers-basehtml#renderTagAttributes()-detail) for details on how attributes are being rendered. + * + * @return string the generated radio button list + */ + public static function activeRadioList($model, $attribute, $items, $options = []) + { + return static::activeListInput('radioList', $model, $attribute, $items, $options); + } + + /** + * Generates a list of input fields. + * This method is mainly called by [[activeRadioList()]] and [[activeCheckboxList()]]. + * @param string $type the input type. This can be 'radioList' or 'checkBoxList'. + * @param Model $model the model object + * @param string $attribute the attribute name or expression. See [\yii\helpers\Html::getAttributeName()](https://www.yiiframework.com/doc/api/2.0/yii-helpers-basehtml#getInputName()-detail) for the format + * about attribute expression. + * @param array $items the data item used to generate the input fields. + * The array keys are the input values, and the array values are the corresponding labels. + * Note that the labels will NOT be HTML-encoded, while the values will. + * @param array $options options (name => config) for the input list. The supported special options + * depend on the input type specified by `$type`. + * @return string the generated input list + */ + protected static function activeListInput($type, $model, $attribute, $items, $options = []) + { + $name = isset($options['name']) ? $options['name'] : static::getInputName($model, $attribute); + $selection = isset($options['value']) ? $options['value'] : static::getAttributeValue($model, $attribute); + if (!array_key_exists('unselect', $options)) { + $options['unselect'] = ''; + } + if (!array_key_exists('id', $options)) { + $options['id'] = static::getInputId($model, $attribute); + } + + return static::$type($name, $selection, $items, $options); + } + + /** + * Generates a list of checkboxes. A checkbox list allows multiple selection. + * As a result, the corresponding submitted value is an array. + * @param string $name the name attribute of each checkbox. + * @param string|array|null $selection the selected value(s). String for single or array for multiple selection(s). + * @param array $items the data item used to generate the checkboxes. + * The array keys are the checkbox values, while the array values are the corresponding labels. + * @param array $options options (name => config) for the checkbox list container tag. + * The following options are specially handled: + * + * - tag: string|false, the tag name of the container element. False to render checkbox without container. + * See also [\yii\helpers\Html::tag()](https://www.yiiframework.com/doc/api/2.0/yii-helpers-basehtml#tag()-detail). + * - unselect: string, the value that should be submitted when none of the checkboxes is selected. + * By setting this option, a hidden input will be generated. + * - encode: boolean, whether to HTML-encode the checkbox labels. Defaults to true. + * This option is ignored if `item` option is set. + * - separator: string, the HTML code that separates items. + * - itemOptions: array, the options for generating the checkbox tag using [\yii\helpers\Html::checkbox()](https://www.yiiframework.com/doc/api/2.0/yii-helpers-basehtml#checkbox()-detail). + * - item: callable, a callback that can be used to customize the generation of the HTML code + * corresponding to a single item in $items. The signature of this callback must be: + * + * ```php + * function ($index, $label, $name, $checked, $value) + * ``` + * + * where $index is the zero-based index of the checkbox in the whole list; $label + * is the label for the checkbox; and $name, $value and $checked represent the name, + * value and the checked status of the checkbox input, respectively. + * + * See [\yii\helpers\Html::renderTagAttributes()](https://www.yiiframework.com/doc/api/2.0/yii-helpers-basehtml#renderTagAttributes()-detail) for details on how attributes are being rendered. + * + * @return string the generated checkbox list + */ + public static function checkboxList($name, $selection = null, $items = [], $options = []) + { + if (substr($name, -2) !== '[]') { + $name .= '[]'; + } + if (ArrayHelper::isTraversable($selection)) { + $selection = array_map('strval', (array)$selection); + } + + $formatter = ArrayHelper::remove($options, 'item'); + $itemOptions = ArrayHelper::remove($options, 'itemOptions', []); + $encode = ArrayHelper::remove($options, 'encode', true); + $separator = ArrayHelper::remove($options, 'separator', "\n"); + $tag = ArrayHelper::remove($options, 'tag', 'div'); + + $lines = []; + $index = 0; + foreach ($items as $value => $label) { + $checked = $selection !== null && + (!ArrayHelper::isTraversable($selection) && !strcmp($value, $selection) + || ArrayHelper::isTraversable($selection) && ArrayHelper::isIn((string)$value, $selection)); + if ($formatter !== null) { + $lines[] = call_user_func($formatter, $index, $label, $name, $checked, $value); + } else { + $lines[] = Html::tag('div', static::checkbox($name, $checked, array_merge($itemOptions, [ + 'value' => $value, + 'label' => $encode ? static::encode($label) : $label, + ]))); + } + $index++; + } + + if (isset($options['unselect'])) { + // add a hidden field so that if the list box has no option being selected, it still submits a value + $name2 = substr($name, -2) === '[]' ? substr($name, 0, -2) : $name; + $hidden = static::hiddenInput($name2, $options['unselect']); + unset($options['unselect']); + } else { + $hidden = ''; + } + + $visibleContent = implode($separator, $lines); + + if ($tag === false) { + return $hidden . $visibleContent; + } + + return $hidden . static::tag($tag, $visibleContent, $options); + } + + /** + * Generates a list of radio buttons. + * A radio button list is like a checkbox list, except that it only allows single selection. + * @param string $name the name attribute of each radio button. + * @param string|array|null $selection the selected value(s). String for single or array for multiple selection(s). + * @param array $items the data item used to generate the radio buttons. + * The array keys are the radio button values, while the array values are the corresponding labels. + * @param array $options options (name => config) for the radio button list container tag. + * The following options are specially handled: + * + * - tag: string|false, the tag name of the container element. False to render radio buttons without container. + * See also [\yii\helpers\Html::tag()](https://www.yiiframework.com/doc/api/2.0/yii-helpers-basehtml#tag()-detail). + * - unselect: string, the value that should be submitted when none of the radio buttons is selected. + * By setting this option, a hidden input will be generated. + * - encode: boolean, whether to HTML-encode the checkbox labels. Defaults to true. + * This option is ignored if `item` option is set. + * - separator: string, the HTML code that separates items. + * - itemOptions: array, the options for generating the radio button tag using [[radio()]]. + * - item: callable, a callback that can be used to customize the generation of the HTML code + * corresponding to a single item in $items. The signature of this callback must be: + * + * ```php + * function ($index, $label, $name, $checked, $value) + * ``` + * + * where $index is the zero-based index of the radio button in the whole list; $label + * is the label for the radio button; and $name, $value and $checked represent the name, + * value and the checked status of the radio button input, respectively. + * + * See [\yii\helpers\Html::renderTagAttributes()](https://www.yiiframework.com/doc/api/2.0/yii-helpers-basehtml#renderTagAttributes()-detail) for details on how attributes are being rendered. + * + * @return string the generated radio button list + */ + public static function radioList($name, $selection = null, $items = [], $options = []) + { + if (ArrayHelper::isTraversable($selection)) { + $selection = array_map('strval', (array)$selection); + } + + $formatter = ArrayHelper::remove($options, 'item'); + $itemOptions = ArrayHelper::remove($options, 'itemOptions', []); + $encode = ArrayHelper::remove($options, 'encode', true); + $separator = ArrayHelper::remove($options, 'separator', "\n"); + $tag = ArrayHelper::remove($options, 'tag', 'div'); + // add a hidden field so that if the list box has no option being selected, it still submits a value + $hidden = isset($options['unselect']) ? static::hiddenInput($name, $options['unselect']) : ''; + unset($options['unselect']); + + $lines = []; + $index = 0; + foreach ($items as $value => $label) { + $checked = $selection !== null && + (!ArrayHelper::isTraversable($selection) && !strcmp($value, $selection) + || ArrayHelper::isTraversable($selection) && ArrayHelper::isIn((string)$value, $selection)); + if ($formatter !== null) { + $lines[] = call_user_func($formatter, $index, $label, $name, $checked, $value); + } else { + $lines[] = Html::tag('div', static::radio($name, $checked, array_merge($itemOptions, [ + 'value' => $value, + 'label' => $encode ? static::encode($label) : $label, + ]))); + } + $index++; + } + $visibleContent = implode($separator, $lines); + + if ($tag === false) { + return $hidden . $visibleContent; + } + + return $hidden . static::tag($tag, $visibleContent, $options); + } + + /** + * Generates a radio button input. + * @param string $name the name attribute. + * @param bool $checked whether the radio button should be checked. + * @param array $options the tag options in terms of name-value pairs. + * See [[booleanInput()]] for details about accepted attributes. + * + * @return string the generated radio button tag + */ + public static function radio($name, $checked = false, $options = []) + { + return static::booleanInput('radio', $name, $checked, $options); + } + + /** + * Generates a boolean input. + * @param string $type the input type. This can be either `radio` or `checkbox`. + * @param string $name the name attribute. + * @param bool $checked whether the checkbox should be checked. + * @param array $options the tag options in terms of name-value pairs. The following options are specially handled: + * + * - uncheck: string, the value associated with the uncheck state of the checkbox. When this attribute + * is present, a hidden input will be generated so that if the checkbox is not checked and is submitted, + * the value of this attribute will still be submitted to the server via the hidden input. + * - label: string, a label displayed next to the checkbox. It will NOT be HTML-encoded. Therefore you can pass + * in HTML code such as an image tag. If this is is coming from end users, you should [\yii\helpers\Html::encode()](https://www.yiiframework.com/doc/api/2.0/yii-helpers-basehtml#encode()-detail) it to prevent XSS attacks. + * When this option is specified, the checkbox will be enclosed by a label tag. + * - labelOptions: array, the HTML attributes for the label tag. Do not set this option unless you set the "label" option. + * + * The rest of the options will be rendered as the attributes of the resulting checkbox tag. The values will + * be HTML-encoded using [\yii\helpers\Html::encode()](https://www.yiiframework.com/doc/api/2.0/yii-helpers-basehtml#encode()-detail). If a value is null, the corresponding attribute will not be rendered. + * See [\yii\helpers\Html::renderTagAttributes()](https://www.yiiframework.com/doc/api/2.0/yii-helpers-basehtml#renderTagAttributes()-detail) for details on how attributes are being rendered. + * + * @return string the generated checkbox tag + * @since 2.0.9 + */ + protected static function booleanInput($type, $name, $checked = false, $options = []) + { + $options['checked'] = (bool) $checked; + $value = array_key_exists('value', $options) ? $options['value'] : '1'; + if (isset($options['uncheck'])) { + // add a hidden field so that if the checkbox is not selected, it still submits a value + $hiddenOptions = []; + if (isset($options['form'])) { + $hiddenOptions['form'] = $options['form']; + } + $hidden = static::hiddenInput($name, $options['uncheck'], $hiddenOptions); + unset($options['uncheck']); + } else { + $hidden = ''; + } + if (isset($options['label'])) { + $label = Html::tag('span', $options['label']); + $labelOptions = isset($options['labelOptions']) ? $options['labelOptions'] : []; + unset($options['label'], $options['labelOptions']); + $content = static::label(static::input($type, $name, $value, $options) . ' ' . $label, null, $labelOptions); + return $hidden . $content; + } + + return $hidden . static::input($type, $name, $value, $options); + } } diff --git a/src/lib/MaterializeWidgetTrait.php b/src/lib/MaterializeWidgetTrait.php index ceeeb81..10225d7 100755 --- a/src/lib/MaterializeWidgetTrait.php +++ b/src/lib/MaterializeWidgetTrait.php @@ -10,6 +10,7 @@ use macgyer\yii2materializecss\assets\MaterializePluginAsset; use Yii; use yii\helpers\Json; +use yii\web\View; /** * MaterializeWidgetTrait provides the basics for all Materialize widgets features. @@ -72,6 +73,7 @@ public function init() */ protected function registerPlugin($name, $selector = null) { + /** @var View $view */ $view = $this->getView(); MaterializePluginAsset::register($view); @@ -83,9 +85,10 @@ protected function registerPlugin($name, $selector = null) } if ($this->clientOptions !== false) { - $options = empty($this->clientOptions) ? '' : Json::htmlEncode($this->clientOptions); - $js = "jQuery('$selector').$name($options);"; - $view->registerJs($js); + $options = empty($this->clientOptions) ? '{}' : Json::htmlEncode($this->clientOptions); + + $js = "document.addEventListener('DOMContentLoaded', function() {M.$name.init(document.querySelectorAll('$selector'), $options);});"; + $view->registerJs($js, View::POS_END); } $this->registerClientEvents(); @@ -97,12 +100,23 @@ protected function registerPlugin($name, $selector = null) protected function registerClientEvents() { if (!empty($this->clientEvents)) { + /** @var View $view */ + $view = $this->getView(); $id = $this->options['id']; - $js = []; + $js[] = "var elem_$id = document.getElementById('$id');"; foreach ($this->clientEvents as $event => $handler) { - $js[] = "jQuery('#$id').on('$event', $handler);"; + $js[] = "elem_$id.addEventListener('$event', $handler);"; } - $this->getView()->registerJs(implode("\n", $js)); + $view->registerJs(implode("\n", $js), View::POS_END); } } -} \ No newline at end of file + + /** + * @return string + */ + protected function getUniqueId($prefix = 'u_') + { + $uniqid = sha1(uniqid($prefix, true)); + return "{$prefix}{$uniqid}"; + } +} diff --git a/src/widgets/Alert.php b/src/widgets/Alert.php index f007ddf..728565e 100755 --- a/src/widgets/Alert.php +++ b/src/widgets/Alert.php @@ -13,11 +13,11 @@ use yii\helpers\ArrayHelper; /** - * Alert renders Yii's session flash messages. - * - * All flash messages are displayed in the sequence they were assigned using - * [yii\web\Session::setFlash()](http://www.yiiframework.com/doc-2.0/yii-web-session.html#setFlash()-detail). - * + * Alert renders Yii's session flash messages. + * + * All flash messages are displayed in the sequence they were assigned using + * [yii\web\Session::setFlash()](http://www.yiiframework.com/doc-2.0/yii-web-session.html#setFlash()-detail). + * * You can set messages as follows: * * ```php @@ -62,7 +62,7 @@ class Alert extends BaseWidget /** * @var array the HTML attributes for the widget container tag. - * @see [yii\helpers\BaseHtml::renderTagAttributes()](http://www.yiiframework.com/doc-2.0/yii-helpers-basehtml.html#renderTagAttributes()-detail) for details on + * @see [yii\helpers\BaseHtml::renderTagAttributes()](http://www.yiiframework.com/doc-2.0/yii-helpers-basehtml.html#renderTagAttributes()-detail) for details on * how attributes are being rendered. */ public $options = []; @@ -81,8 +81,7 @@ public function init() /** * Executes the widget. - * @return string the result of widget execution to be outputted. - * + * * @uses [yii\web\Session](http://www.yiiframework.com/doc-2.0/yii-web-session.html) */ public function run() diff --git a/src/widgets/Button.php b/src/widgets/Button.php index 8859d80..b3e1bc1 100755 --- a/src/widgets/Button.php +++ b/src/widgets/Button.php @@ -21,7 +21,7 @@ * * The button can be displayed with an optional icon. This class uses the [[Icon|Icon]] widget to show icons. * - * @see http://materializecss.com/buttons.html + * @see https://materializecss.com/buttons.html * @author Christoph Erdmann * @package widgets */ @@ -42,6 +42,21 @@ class Button extends BaseWidget */ const TYPE_FLAT = 'flat'; + /** + * Sets the [[size]] of the button to the default size. + */ + const SIZE_DEFAULT = 'default'; + + /** + * Sets the [[size]] of the button to "small". + */ + const SIZE_SMALL = 'small'; + + /** + * Sets the [[size]] of the button to "large". + */ + const SIZE_LARGE = 'large'; + /** * @var string the tag used to render the button. */ @@ -88,9 +103,17 @@ class Button extends BaseWidget public $type = self::TYPE_RAISED; /** - * @var boolean whether the button shall be of larger size. + * @var string the size of button to be rendered. + * + * The following options are supported: + * - default + * - small + * - large + * + * This property defaults to "default". To set the type, use the corresponding `TYPE_*` constant of this class. + * If no type from this range is given, the button will be of the "default" type. */ - public $large = false; + public $size = self::SIZE_DEFAULT; /** * @var boolean whether the button shall be disabled. @@ -113,10 +136,17 @@ public function init() break; } - if ($this->large) { - Html::addCssClass($this->options, ['btn_size' => 'btn-large']); + switch ($this->size) { + case self::SIZE_SMALL: + case self::SIZE_LARGE: + Html::addCssClass($this->options, ['btn_size' => "btn-$this->size"]); + break; } +// if ($this->large) { +// Html::addCssClass($this->options, ['btn_size' => 'btn-large']); +// } + if ($this->disabled) { Html::addCssClass($this->options, ['btn_disabled' => 'disabled']); } diff --git a/src/widgets/Collapsible.php b/src/widgets/Collapsible.php index 0d41a8a..fbb5ee3 100644 --- a/src/widgets/Collapsible.php +++ b/src/widgets/Collapsible.php @@ -44,13 +44,14 @@ * 'tag' => 'p', * 'data-body-category' => 'example', * ], + * 'options' => ['class' => 'active'], // to make this item pre-selected * ], * ] * ``` * @author Christoph Erdmann * @package widgets * - * @see http://materializecss.com/collapsible.html + * @see https://materializecss.com/collapsible.html */ class Collapsible extends BaseWidget { @@ -91,7 +92,12 @@ public function init() if ($this->isPopoutStyle) { Html::addCssClass($this->options, ['popout' => 'popout']); } - $this->options['data-collapsible'] = $this->type; + + if ($this->type == self::TYPE_EXPANDABLE) { + $this->clientOptions['accordion'] = false; + } + + $this->registerPlugin('Collapsible'); } /** diff --git a/src/widgets/Icon.php b/src/widgets/Icon.php index 0b84c54..e77f392 100755 --- a/src/widgets/Icon.php +++ b/src/widgets/Icon.php @@ -18,20 +18,20 @@ * Please note that the Materialize icons are shipped in a separate font file. This font file is automatically registered * by the [[\macgyer\yii2materializecss\assets\MaterializeAsset|MaterializeAsset]]. * - * If you do not load the default [[\macgyer\yii2materializecss\assets\MaterializeAsset|MaterializeAsset]] make sure to at least load - * [[\macgyer\yii2materializecss\assets\MaterializeFontAsset|MaterializeFontAsset]] (or another source providing the font file) to correctly + * If you do not load the default [[\macgyer\yii2materializecss\assets\MaterializeAsset|MaterializeAsset]] make sure to at least load + * [[\macgyer\yii2materializecss\assets\MaterializeFontAsset|MaterializeFontAsset]] (or another source providing the font file) to correctly * display the icons. * * @author Christoph Erdmann * @package widgets - * @see http://materializecss.com/icons.html + * @see https://materializecss.com/icons.html */ class Icon extends BaseWidget { /** * @var string the name of the icon. * - * @see http://materializecss.com/icons.html + * @see https://materializecss.com/icons.html */ public $name; diff --git a/src/widgets/Modal.php b/src/widgets/Modal.php index f24cb1c..577df3d 100755 --- a/src/widgets/Modal.php +++ b/src/widgets/Modal.php @@ -37,7 +37,7 @@ * ``` * @author Christoph Erdmann * @package widgets - * @see http://materializecss.com/modals.html + * @see https://materializecss.com/modals.html */ class Modal extends BaseWidget { @@ -107,7 +107,7 @@ class Modal extends BaseWidget * - fixedFooter * - bottomSheet * - * @see http://materializecss.com/modals.html + * @see https://materializecss.com/modals.html */ public $modalType = self::TYPE_LEAN; @@ -173,6 +173,41 @@ class Modal extends BaseWidget */ public $footerOptions = []; + /** + * @var float the opacity of the Modal overlay. Valid values are 0 through 1. + */ + public $overlayOpacity = 0.5; + + /** + * @var int duration of the opening transition in ms. + */ + public $inDuration = 250; + + /** + * @var int duration of the closing transition in ms. + */ + public $outDuration = 250; + + /** + * @var boolean whether the page scrolling is disabled when the Modal is open. + */ + public $preventScrolling = true; + + /** + * @var boolean whether the Modal can be closed by keyboard or click. + */ + public $dismissible = true; + + /** + * @var string|mixed the starting top offset. + */ + public $startingTopOffset = '4%'; + + /** + * @var string|mixed the ending top offset. + */ + public $endingTopOffset = '10%'; + /** * Initializes the widget. * @uses [[renderCloseButton()]] @@ -203,7 +238,7 @@ public function init() echo $html; - $this->registerPlugin('modal'); + $this->registerPlugin('Modal'); } /** @@ -346,8 +381,12 @@ protected function initDefaults() ], $this->toggleButton); } - if ($this->clientOptions !== false) { - $this->clientOptions = ArrayHelper::merge(['show' => false], $this->clientOptions); - } + $this->clientOptions['opacity'] = $this->overlayOpacity; + $this->clientOptions['inDuration'] = $this->inDuration; + $this->clientOptions['outDuration'] = $this->outDuration; + $this->clientOptions['preventScrolling'] = $this->preventScrolling; + $this->clientOptions['dismissible'] = $this->dismissible; + $this->clientOptions['startingTop'] = $this->startingTopOffset; + $this->clientOptions['endingTop'] = $this->endingTopOffset; } } diff --git a/src/widgets/Progress.php b/src/widgets/Progress.php index 7d22a37..82fdf1f 100755 --- a/src/widgets/Progress.php +++ b/src/widgets/Progress.php @@ -43,6 +43,16 @@ */ class Progress extends BaseWidget { + /** + * Sets the [[type]] of the progress bar to 'determinate'. + */ + const TYPE_DETERMINATE = 'determinate'; + + /** + * Sets the [[type]] of the progress bar to 'indeterminate'. This is the default. + */ + const TYPE_INDETERMINATE = 'indeterminate'; + /** * @var array the HTML attributes for the widget container tag * @@ -67,9 +77,9 @@ class Progress extends BaseWidget * - indeterminate (default) * - determinate * - * @see http://materializecss.com/preloader.html + * @see https://materializecss.com/preloader.html */ - public $type = 'indeterminate'; + public $type = self::TYPE_INDETERMINATE; /** * @var integer the (initial) value for 'determinate' progress bars. @@ -81,7 +91,7 @@ class Progress extends BaseWidget *
* ``` * - * @see http://materializecss.com/preloader.html + * @see https://materializecss.com/preloader.html */ public $value = 0; @@ -95,7 +105,7 @@ public function init() Html::addCssClass($this->options, ['widget' => 'progress']); Html::addCssClass($this->progressOptions, ['type' => $this->type]); - if ($this->type === 'determinate') { + if ($this->type === self::TYPE_DETERMINATE) { Html::addCssStyle($this->progressOptions, ['width' => $this->value . '%']); } } diff --git a/src/widgets/Spinner.php b/src/widgets/Spinner.php index 097215e..c33861b 100755 --- a/src/widgets/Spinner.php +++ b/src/widgets/Spinner.php @@ -81,7 +81,7 @@ class Spinner extends BaseWidget * * If this is set to "true" the spinner will continously alternate its colors between blue, red, yellow and green. * - * @see http://materializecss.com/preloader.html + * @see https://materializecss.com/preloader.html */ public $flashColors = false; diff --git a/src/widgets/Chip.php b/src/widgets/StaticChip.php old mode 100755 new mode 100644 similarity index 82% rename from src/widgets/Chip.php rename to src/widgets/StaticChip.php index 1221d51..7f9943d --- a/src/widgets/Chip.php +++ b/src/widgets/StaticChip.php @@ -13,16 +13,17 @@ use yii\helpers\ArrayHelper; /** - * Chip renders small units of information. + * StaticChip renders small units of information. * - * An Usual use case is the displaying of tags or contact information. + * An usual use case is the displaying of contact information. + * If you need tagging support in forms or inputs generally, please use [[\macgyer\yii2materializecss\widgets\form\ChipInput|ChipInput]]. * * @author Christoph Erdmann * - * @see http://materializecss.com/chips.html + * @see https://materializecss.com/chips.html * @package widgets */ -class Chip extends BaseWidget +class StaticChip extends BaseWidget { /** * @var array the HTML attributes for the widget container tag. The following special options are recognized: @@ -59,11 +60,11 @@ class Chip extends BaseWidget /** * @var array the options for the optional [[Icon|Icon]]. * - * If there is an icon present in the chip element, Materialize will + * If there is an icon present in the chip element, Materialize will * treat it as a close (i. e. remove) trigger. * * To specify an [[Icon|Icon]] you can use the following parameters: - * + * * ```php * [ * 'name' => 'name of the icon', // optional, defaults to 'close' @@ -104,29 +105,32 @@ public function init() /** * Executes the widget. * @return string the result of widget execution to be outputted. + * @throws \Exception * @uses [[Icon]] */ public function run() { $tag = ArrayHelper::remove($this->options, 'tag', 'div'); - $html = Html::beginTag($tag, $this->options); + $html[] = Html::beginTag($tag, $this->options); if ($this->imageOptions) { $src = ArrayHelper::remove($this->imageOptions, 'src', ''); - $html .= Html::img($src, $this->imageOptions); + $html[] = Html::img($src, $this->imageOptions); } - $html .= $this->encodeContent ? Html::encode($this->content) : $this->content; + $html[] = $this->encodeContent ? Html::encode($this->content) : $this->content; if ($this->renderIcon) { - $html .= Icon::widget([ + Html::addCssClass($this->icon['options'], ['close-trigger' => 'close']); + + $html[] = Icon::widget([ 'name' => ArrayHelper::getValue($this->icon, 'name', null), 'position' => ArrayHelper::getValue($this->icon, 'position', ''), 'options' => ArrayHelper::getValue($this->icon, 'options', []) ]); } - $html .= Html::endTag($tag); - return $html; + $html[] = Html::endTag($tag); + return implode("\n", $html); } } diff --git a/src/widgets/data/DetailView.php b/src/widgets/data/DetailView.php index e413292..f43af04 100755 --- a/src/widgets/data/DetailView.php +++ b/src/widgets/data/DetailView.php @@ -9,7 +9,7 @@ /** * DetailView displays the detail of a single data model. - * + * * This data model is represented by `$model` (inherited from [yii\widgets\DetailView](http://www.yiiframework.com/doc-2.0/yii-widgets-detailview.html)). * * DetailView is best used for displaying a model in a regular format (e.g. each model attribute @@ -35,7 +35,7 @@ * ], * ]); * ``` - * + * * @see [yii\widgets\DetailView](http://www.yiiframework.com/doc-2.0/yii-widgets-detailview.html) * @author Christoph Erdmann * @package widgets @@ -46,7 +46,7 @@ class DetailView extends \yii\widgets\DetailView /** * @var array the HTML attributes for the container tag of this widget. The "tag" option specifies * what container tag should be used. It defaults to "table" if not set. - * @see [yii\helpers\BaseHtml::renderTagAttributes()](http://www.yiiframework.com/doc-2.0/yii-helpers-basehtml.html#renderTagAttributes()-detail) for details on + * @see [yii\helpers\BaseHtml::renderTagAttributes()](http://www.yiiframework.com/doc-2.0/yii-helpers-basehtml.html#renderTagAttributes()-detail) for details on * how attributes are being rendered. */ public $options = ['class' => 'table striped bordered detail-view']; diff --git a/src/widgets/form/ActiveField.php b/src/widgets/form/ActiveField.php index 72fa484..03f4623 100755 --- a/src/widgets/form/ActiveField.php +++ b/src/widgets/form/ActiveField.php @@ -13,10 +13,6 @@ use yii\helpers\ArrayHelper; use yii\helpers\Json; -// TODO: range with noUiSlider --> own widget -// TODO: checkbox list -// TODO: radio list -// TODO: select ? // TODO: file input @@ -152,7 +148,7 @@ public function init() * To use the HTML5 autocomplete feature, set this option to `on`. To explicitely disable the HTML5 autocomplete, set * this option to `off`. Either `on` or `off` disables the Materialize autocomplete feature. * - * @see http://materializecss.com/forms.html#autocomplete + * @see https://materializecss.com/autocomplete.html */ protected function initAutoComplete(&$options = []) { @@ -172,11 +168,31 @@ protected function initAutoComplete(&$options = []) $autocompleteData['data'] = $autocomplete; $pluginOptions = Json::htmlEncode($autocompleteData); - $js = "$('input.has-autocomplete').autocomplete($pluginOptions);"; + $js = "M.Autocomplete.init(document.querySelectorAll('.has-autocomplete', $pluginOptions))"; $view->registerJs($js); } + /** + * Initializes the Materialize character counter feature. + * + * @param array $options the tag options as name-value-pairs. + * + * @see https://materializecss.com/text-inputs.html#character-counter + */ + protected function initCharacterCounter(&$options = []) + { + $showCharacterCounter = ArrayHelper::getValue($options, 'showCharacterCounter', false); + + if ($showCharacterCounter) { + Html::addCssClass($this->inputOptions, ['character-counter' => 'has-character-counter']); + $js = "M.CharacterCounter.init(document.querySelectorAll('.has-character-counter'))"; + $view = $this->form->getView(); + $view->registerJs($js); + } + } + + /** * Renders the whole field. * This method will generate the label, error tag, input tag and hint tag (if any), and @@ -193,6 +209,7 @@ protected function initAutoComplete(&$options = []) * ``` * * @return string the rendering result + * @throws \Exception */ public function render($content = null) { @@ -248,45 +265,47 @@ public function icon() * Materialize standard to not wrap the checkboxes in labels. * @return $this */ - public function checkbox($options = [], $enclosedByLabel = false) + public function checkbox($options = [], $enclosedByLabel = true) { Html::addCssClass($this->options, ['class' => 'checkbox']); - return parent::checkbox($options, $enclosedByLabel); + Html::removeCssClass($this->options, 'input-field'); + + $this->parts['{input}'] = Html::activeCheckbox($this->model, $this->attribute, $options); + $this->parts['{label}'] = ''; + + if ($this->form->validationStateOn === ActiveForm::VALIDATION_STATE_ON_INPUT) { + $this->addErrorClassIfNeeded($options); + } + + $this->addAriaAttributes($options); + $this->adjustLabelFor($options); + + return $this; } /** - * Renders a drop-down list. - * - * @param array $items the option data items - * @param array $options the tag options in terms of name-value pairs. - * + * Renders a list of checkboxes. + * A checkbox list allows multiple selections. As a result, the corresponding submitted value is an array. + * The selection of the checkbox list is taken from the value of the model attribute. + * @param array $items the data item used to generate the checkboxes. + * The array values are the labels, while the array keys are the corresponding checkbox values. + * @param array $options options (name => config) for the checkbox list. + * For the list of available options please refer to the `$options` parameter of [[\macgyer\yii2materializecss\lib\Html::activeCheckboxList()]]. * @return $this the field object itself. - * - * @see http://www.yiiframework.com/doc-2.0/yii-widgets-activefield.html#dropDownList()-detail */ - public function dropDownList($items, $options = []) + public function checkboxList($items, $options = []) { - $view = $this->form->view; - MaterializePluginAsset::register($view); - $id = $this->getInputId(); + $this->template = "{icon}\n{label}\n{input}\n{hint}\n{error}"; + if ($this->form->validationStateOn === ActiveForm::VALIDATION_STATE_ON_INPUT) { + $this->addErrorClassIfNeeded($options); + } - $js = "$('#$id').material_select()"; - $view->registerJs($js); + Html::addCssClass($this->labelOptions, ['checkboxlist-label' => 'label-checkbox-list']); - return parent::dropDownList($items, $options); - } + $this->addAriaAttributes($options); + $this->parts['{input}'] = Html::activeCheckboxList($this->model, $this->attribute, $items, $options); - /** - * Renders a radio button. - * @param array $options the tag options in terms of name-value pairs. See parent class for more details. - * @param bool $enclosedByLabel whether to enclose the checkbox within the label. This defaults to `false` as it is - * Materialize standard to not wrap the checkboxes in labels. - * @return $this - */ - public function radio($options = [], $enclosedByLabel = false) - { - Html::addCssClass($this->options, ['class' => 'radio']); - return parent::radio($options, $enclosedByLabel); + return $this; } /** @@ -361,6 +380,28 @@ public function datetimeLocalInput($options = []) return parent::input('datetime-local', $options); } + /** + * Renders a drop-down list. + * + * @param array $items the option data items + * @param array $options the tag options in terms of name-value pairs. + * + * @return $this the field object itself. + * + * @see http://www.yiiframework.com/doc-2.0/yii-widgets-activefield.html#dropDownList()-detail + */ + public function dropDownList($items, $options = []) + { + $view = $this->form->view; + MaterializePluginAsset::register($view); + $id = $this->getInputId(); + + $js = "M.FormSelect.init(document.querySelector('#$id'))"; + $view->registerJs($js); + + return parent::dropDownList($items, $options); + } + /** * Renders an email input. * @param array $options the tag options in terms of name-value pairs. These will be rendered as @@ -434,12 +475,64 @@ public function numberInput($options = []) public function passwordInput($options = []) { $options = array_merge($this->inputOptions, $options); + $this->initCharacterCounter($options); $this->adjustLabelFor($options); $this->parts['{input}'] = Html::activePasswordInput($this->model, $this->attribute, $options); return $this; } + /** + * Renders a radio button. + * @param array $options the tag options in terms of name-value pairs. See parent class for more details. + * @param bool $enclosedByLabel whether to enclose the checkbox within the label. This defaults to `false` as it is + * Materialize standard to not wrap the checkboxes in labels. + * @return $this + */ + public function radio($options = [], $enclosedByLabel = true) + { + Html::addCssClass($this->options, ['class' => 'radio']); + Html::removeCssClass($this->options, 'input-field'); + + $this->parts['{input}'] = Html::activeRadio($this->model, $this->attribute, $options); + $this->parts['{label}'] = ''; + + if ($this->form->validationStateOn === ActiveForm::VALIDATION_STATE_ON_INPUT) { + $this->addErrorClassIfNeeded($options); + } + + $this->addAriaAttributes($options); + $this->adjustLabelFor($options); + + return $this; + } + + /** + * Renders a list of radio buttons. + * A radio button list is like a checkbox list, except that it only allows single selection. + * The selection of the radio buttons is taken from the value of the model attribute. + * + * @param array $items the data item used to generate the radio buttons. The array values are the labels, while the + * array keys are the corresponding radio values. + * @param array $options options (name => config) for the radio button list. For the list of available options please + * refer to the `$options` parameter of [[\macgyer\yii2materializecss\lib\Html::activeRadioList()]]. + * @return $this the field object itself. + */ + public function radioList($items, $options = []) + { + $this->template = "{icon}\n{label}\n{input}\n{hint}\n{error}"; + if ($this->form->validationStateOn === ActiveForm::VALIDATION_STATE_ON_INPUT) { + $this->addErrorClassIfNeeded($options); + } + + Html::addCssClass($this->labelOptions, ['radiolist-label' => 'label-radio-list']); + + $this->addAriaAttributes($options); + $this->parts['{input}'] = Html::activeRadioList($this->model, $this->attribute, $items, $options); + + return $this; + } + /** * Renders a range input. * @param array $options the tag options in terms of name-value pairs. These will be rendered as @@ -490,7 +583,7 @@ public function telInput($options = []) } /** - * Renders a text input. + * Renders a textarea. * @param array $options the tag options in terms of name-value pairs. These will be rendered as * the attributes of the resulting tag. The values will be HTML-encoded using [\yii\helpers\BaseHtml::encode()](http://www.yiiframework.com/doc-2.0/yii-helpers-basehtml.html#encode()-detail). * @@ -508,18 +601,20 @@ public function telInput($options = []) * @see http://materializecss.com/forms.html#autocomplete * @see https://www.w3.org/TR/html5/forms.html#attr-fe-autocomplete */ - public function textInput($options = []) + public function textarea($options = []) { $this->initAutoComplete($options); + $this->initCharacterCounter($options); + Html::addCssClass($options, ['textarea' => 'materialize-textarea']); $options = array_merge($this->inputOptions, $options); $this->adjustLabelFor($options); - $this->parts['{input}'] = Html::activeTextInput($this->model, $this->attribute, $options); + $this->parts['{input}'] = Html::activeTextarea($this->model, $this->attribute, $options); return $this; } /** - * Renders a textarea. + * Renders a text input. * @param array $options the tag options in terms of name-value pairs. These will be rendered as * the attributes of the resulting tag. The values will be HTML-encoded using [\yii\helpers\BaseHtml::encode()](http://www.yiiframework.com/doc-2.0/yii-helpers-basehtml.html#encode()-detail). * @@ -537,13 +632,13 @@ public function textInput($options = []) * @see http://materializecss.com/forms.html#autocomplete * @see https://www.w3.org/TR/html5/forms.html#attr-fe-autocomplete */ - public function textarea($options = []) + public function textInput($options = []) { $this->initAutoComplete($options); - Html::addCssClass($options, ['textarea' => 'materialize-textarea']); + $this->initCharacterCounter($options); $options = array_merge($this->inputOptions, $options); $this->adjustLabelFor($options); - $this->parts['{input}'] = Html::activeTextarea($this->model, $this->attribute, $options); + $this->parts['{input}'] = Html::activeTextInput($this->model, $this->attribute, $options); return $this; } @@ -601,21 +696,4 @@ public function weekInput($options = []) return parent::input('week', $options); } - - /** - * Builds a radio list - */ -// public function radioList($items, $options = []) -// { -// $defaultOptions = [ -// 'item' => function($index, $label, $name, $checked, $value) { -// return Html::radio($name,$checked,['value'=>$value,'id'=>$name.$index]) . Html::label($label,$name.$index); -// return $return; -// }, -// 'class'=>'input-list-wrapper' -// ]; -// $options = array_merge($defaultOptions, $options); -// -// return parent::radioList($items,$options); -// } } diff --git a/src/widgets/form/ActiveForm.php b/src/widgets/form/ActiveForm.php index 59782f8..7e10aad 100755 --- a/src/widgets/form/ActiveForm.php +++ b/src/widgets/form/ActiveForm.php @@ -20,7 +20,7 @@ class ActiveForm extends \yii\widgets\ActiveForm * @var string the default field class name when calling [[field()]] to create a new field. * @see http://www.yiiframework.com/doc-2.0/yii-widgets-activeform.html#$fieldConfig-detail */ - public $fieldClass = 'macgyer\yii2materializecss\widgets\form\ActiveField'; + public $fieldClass = ActiveField::class; /** * @var string the CSS class that is added to a field container when the associated attribute has validation error. diff --git a/src/widgets/form/ChipInput.php b/src/widgets/form/ChipInput.php new file mode 100644 index 0000000..8c44207 --- /dev/null +++ b/src/widgets/form/ChipInput.php @@ -0,0 +1,131 @@ + + * @package widgets + * @subpackage form + * + * @see https://materializecss.com/chips.html#basic + */ +class ChipInput extends BaseInputWidget +{ + /** + * @var array the HTML attributes for the widget container tag. The following special options are recognized: + * + * - tag: string, defaults to "div", the name of the container tag. + * + * @see [yii\helpers\BaseHtml::renderTagAttributes()](http://www.yiiframework.com/doc-2.0/yii-helpers-basehtml.html#renderTagAttributes()-detail) + * for details on how attributes are being rendered. + */ + public $containerOptions = []; + + /** + * @var boolean whether to render an hidden input field to hold the chips data. + * If you need an input field which is associated with your model class and to which you can assign the actual chips + * data via JS, set this option to 'true'. + */ + public $renderHiddenInput = false; + + /** + * @var array the HTML attributes for the actual input element. + * + * @see [yii\helpers\BaseHtml::renderTagAttributes()](http://www.yiiframework.com/doc-2.0/yii-helpers-basehtml.html#renderTagAttributes()-detail) + * for details on how attributes are being rendered. + */ + public $inputOptions = []; + + /** + * @var array the items (Chips). + * + * Each item is an array with the following keys possible: + * - tag: string, required, the Chip content + * - image: string, optional, an optional image source + */ + public $items = []; + + /** + * @var string the placeholder when there are no tags. + */ + public $placeholder; + + /** + * @var string the placeholder for every additional tag. + */ + public $secondaryPlaceholder; + + /** + * @var array the autocomplete data. + * @see https://materializecss.com/autocomplete.html + */ + public $autocompleteOptions = []; + + /** + * Initialize the widget. + */ + public function init() + { + parent::init(); + + if (!isset($this->containerOptions['id'])) { + $this->containerOptions['id'] = $this->getId(); + } + Html::addCssClass($this->containerOptions, ['widget-container' => 'chips-container']); + + if ($this->items) { + $this->clientOptions['data'] = $this->items; + } + if ($this->autocompleteOptions) { + $this->clientOptions['autocompleteOptions'] = $this->autocompleteOptions; + } + if ($this->placeholder) { + $this->clientOptions['placeholder'] = $this->placeholder; + } + if ($this->secondaryPlaceholder) { + $this->clientOptions['secondaryPlaceholder'] = $this->secondaryPlaceholder; + } + + $this->registerPlugin('Chips', "#{$this->containerOptions['id']} .chips"); + } + + /** + * Execute the widget. + * + * @return string the widget markup. + */ + public function run() + { + $tag = ArrayHelper::remove($this->containerOptions, 'tag', 'div'); + $html[] = Html::beginTag($tag, $this->containerOptions); + if ($this->renderHiddenInput) { + $html[] = $this->renderHiddenInput(); + } + + $html[] = Html::beginTag('div', ['class' => 'chips']); + + $html[] = Html::endTag('div'); + $html[] = Html::endTag($tag); + return implode("\n", $html); + } + + /** + * Renders a hidden input field which can be used to assign the chips data to via JS. + * + * @return string the input field markup. + */ + protected function renderHiddenInput() + { + if ($this->hasModel()) { + return Html::activeHiddenInput($this->model, $this->attribute, $this->options); + } else { + return Html::hiddenInput($this->name, $this->value, $this->options); + } + } +} diff --git a/src/widgets/form/DatePicker.php b/src/widgets/form/DatePicker.php index c50cd26..95a1413 100755 --- a/src/widgets/form/DatePicker.php +++ b/src/widgets/form/DatePicker.php @@ -13,12 +13,9 @@ /** * DatePicker renders an date picker input element. * - * Materialize is shipped with the JS library pickadate.js. Please see the [official documentation](http://amsul.ca/pickadate.js/) - * for all options and details. + * Materialize is using a modified version of the JS library pickadate.js. * - * Be aware that not all options of pickadate are currently supported by the Materialize implementation. - * - * @see http://amsul.ca/pickadate.js/ + * @see https://materializecss.com/pickers.html#date-picker * @author Christoph Erdmann * @package widgets * @subpackage form @@ -27,17 +24,15 @@ class DatePicker extends BaseInputWidget { /** * @var array the options for the underlying datepicker JS plugin. - * Please refer to the corresponding [documentation web page](http://amsul.ca/pickadate.js/). * - * @see http://amsul.ca/pickadate.js/date/#options + * @see https://materializecss.com/pickers.html#date-picker */ public $clientOptions = []; /** * @var array the event handlers for the underlying date picker JS plugin. - * Please refer to the corresponding [documentation web page](http://amsul.ca/pickadate.js/). * - * @see http://amsul.ca/pickadate.js/date/#events + * @see https://materializecss.com/pickers.html#date-picker */ public $clientEvents = []; @@ -47,16 +42,16 @@ class DatePicker extends BaseInputWidget */ public function run() { - $this->registerPlugin('pickadate'); + $this->registerPlugin('Datepicker', '.datepicker'); Html::addCssClass($this->options, 'datepicker'); if ($this->hasModel()) { $this->options['data-value'] = isset($this->value) ? $this->value : Html::getAttributeValue($this->model, $this->attribute); - return Html::activeInput('date', $this->model, $this->attribute, $this->options); + return Html::activeInput('text', $this->model, $this->attribute, $this->options); } else { $this->options['data-value'] = $this->value; - return Html::input('date', $this->name, $this->value, $this->options); + return Html::input('text', $this->name, $this->value, $this->options); } } } diff --git a/src/widgets/form/RangeInput.php b/src/widgets/form/RangeInput.php index 238b0a7..7174191 100644 --- a/src/widgets/form/RangeInput.php +++ b/src/widgets/form/RangeInput.php @@ -28,7 +28,7 @@ * @package widgets * @subpackage form * - * @see http://materializecss.com/forms.html#range + * @see https://materializecss.com/range.html * @see https://refreshless.com/nouislider/ */ class RangeInput extends BaseInputWidget @@ -189,6 +189,14 @@ protected function renderHtml5RangeInput() { $html[] = Html::beginTag('div', ['class' => 'range-field']); + // workaround for: https://github.com/Dogfalo/materialize/issues/5761 + if (!isset($this->inputOptions['min'])) { + $this->inputOptions['min'] = 0; + } + if (!isset($this->inputOptions['max'])) { + $this->inputOptions['max'] = 100; + } + if ($this->hasModel()) { $html[] = Html::activeInput('range', $this->model, $this->attribute, $this->inputOptions); } else { @@ -225,7 +233,7 @@ protected function renderNoUiSlider() protected function renderHiddenInput() { if ($this->hasModel()) { - return Html::activeTextInput($this->model, $this->attribute, $this->inputOptions); + return Html::activeHiddenInput($this->model, $this->attribute, $this->inputOptions); } else { return Html::hiddenInput($this->name, $this->value, $this->inputOptions); } @@ -240,7 +248,7 @@ protected function registerClientScripts() NoUiSliderAsset::register($view); $id = $this->sliderOptions['id']; - $varName = 'slider_' . sha1(uniqid()); + $varName = $this->getUniqueId('slider_'); if ($this->clientOptions !== false) { $options = empty($this->clientOptions) ? '{}' : Json::htmlEncode($this->clientOptions); diff --git a/src/widgets/form/Select.php b/src/widgets/form/Select.php index f9b6c55..2c46806 100755 --- a/src/widgets/form/Select.php +++ b/src/widgets/form/Select.php @@ -46,7 +46,7 @@ class Select extends BaseInputWidget * ], * * // If you provide an array as value and do not have an 'option' key present, the value will be treated as nested - * // values. Every rule explained above apply to the sub-array. Every array value will be rendered as an