| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245 |
- <?php
- namespace Dcat\Admin\Form\Field;
- use Dcat\Admin\Admin;
- use Dcat\Admin\Exception\RuntimeException;
- use Dcat\Admin\Form;
- use Illuminate\Support\Arr;
- /**
- * @property Form $form
- */
- trait CanCascadeFields
- {
- /**
- * @var array
- */
- protected $conditions = [];
- /**
- * @var array
- */
- protected $cascadeGroups = [];
- /**
- * @param $operator
- * @param $value
- * @param $closure
- * @return $this
- */
- public function when($operator, $value, $closure = null)
- {
- if (func_num_args() == 2) {
- $closure = $value;
- $value = $operator;
- $operator = $this->getDefaultOperator();
- }
- $this->formatValues($operator, $value);
- $this->addDependents($operator, $value, $closure);
- return $this;
- }
- protected function getDefaultOperator()
- {
- if ($this instanceof MultipleSelect || $this instanceof Checkbox) {
- return 'in';
- }
- return '=';
- }
- /**
- * @param string $operator
- * @param mixed $value
- */
- protected function formatValues(string $operator, &$value)
- {
- if (in_array($operator, ['in', 'notIn'])) {
- $value = Arr::wrap($value);
- }
- if (is_array($value)) {
- $value = array_map('strval', $value);
- } else {
- $value = strval($value);
- }
- }
- /**
- * @param string $operator
- * @param mixed $value
- * @param \Closure $closure
- */
- protected function addDependents(string $operator, $value, \Closure $closure)
- {
- $this->conditions[] = compact('operator', 'value', 'closure');
- ($this->parent ?: $this->form)->cascadeGroup($closure, [
- 'column' => $this->column(),
- 'index' => count($this->conditions) - 1,
- 'class' => $this->getCascadeClass($value, $operator),
- ]);
- }
- /**
- * @param mixed $value
- * @return string
- */
- protected function getCascadeClass($value, string $operator)
- {
- if (is_array($value)) {
- $value = implode('-', $value);
- }
- $map = [
- '=' => '0',
- '>' => '1',
- '<' => '2',
- '!=' => '3',
- 'in' => '4',
- 'notIn' => '5',
- '>=' => '6',
- '<=' => '7',
- 'has' => '8',
- ];
- return str_replace(
- '.',
- '',
- sprintf('cascade-%s-%s-%s', str_replace(' ', '-', $this->getElementClassString()), $value, $map[$operator])
- );
- }
- protected function addCascadeScript()
- {
- if (! $script = $this->getCascadeScript()) {
- return;
- }
- Admin::script(
- <<<JS
- Dcat.init('{$this->getElementClassSelector()}', function (\$this) {
- {$script}
- });
- JS
- );
- }
- /**
- * Add cascade scripts to contents.
- *
- * @return string
- */
- protected function getCascadeScript()
- {
- if (empty($this->conditions)) {
- return;
- }
- $cascadeGroups = collect($this->conditions)->map(function ($condition) {
- return [
- 'class' => $this->getCascadeClass($condition['value'], $condition['operator']),
- 'operator' => $condition['operator'],
- 'value' => $condition['value'],
- ];
- })->toJson();
- return <<<JS
- (function () {
- var compare = function (a, b, o) {
- if (! $.isArray(b)) {
- return operator_table[o](a, b)
- }
- if (o === '!=') {
- var result = true;
- for (var i in b) {
- if (! operator_table[o](a, b[i])) {
- result = false;
- break;
- }
- }
- return result;
- }
- for (var i in b) {
- if (operator_table[o](a, b[i])) {
- return true;
- }
- }
- };
- var operator_table = {
- '=': function(a, b) {
- if ($.isArray(a) && $.isArray(b)) {
- return $(a).not(b).length === 0 && $(b).not(a).length === 0;
- }
- return String(a) === String(b);
- },
- '>': function(a, b) {
- return a > b;
- },
- '<': function(a, b) {
- return a < b;
- },
- '>=': function(a, b) { return a >= b; },
- '<=': function(a, b) { return a <= b; },
- '!=': function(a, b) {
- return ! operator_table['='](a, b);
- },
- 'in': function(a, b) { return Dcat.helpers.inObject(a, String(b), true); },
- 'notIn': function(a, b) { return ! Dcat.helpers.inObject(a, String(b), true); },
- 'has': function(a, b) { return Dcat.helpers.inObject(b, String(b), true); },
- };
- var cascade_groups = {$cascadeGroups}, event = '{$this->cascadeEvent}';
- \$this.on(event, function (e) {
- {$this->getFormFrontValue()}
- let parent = \$this.closest('.fields-group');
- if (parent.length === 0){
- parent = \$this.closest('form');
- }
- cascade_groups.forEach(function (event) {
- var group = parent.find('div.cascade-group.'+event.class);
- if (compare(checked, event.value, event.operator)) {
- group.removeClass('d-none');
- } else {
- group.addClass('d-none');
- }
- });
- }).trigger(event);
- })();
- JS;
- }
- /**
- * @return string
- */
- protected function getFormFrontValue()
- {
- switch (get_class($this)) {
- case Select::class:
- case MultipleSelect::class:
- return 'var checked = $(this).val();';
- case Radio::class:
- return <<<JS
- var checked = \$(this).closest('.form-group').find(':checked').val();
- JS;
- case Checkbox::class:
- return <<<JS
- var checked = \$this.closest('.form-group').find(':checked').map(function(){
- return $(this).val();
- }).get();
- JS;
- default:
- throw new RuntimeException('Invalid form field type');
- }
- }
- }
|