Tab.php 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. <?php
  2. namespace Dcat\Admin\Form;
  3. use Dcat\Admin\Admin;
  4. use Dcat\Admin\Form;
  5. use Dcat\Admin\Widgets\Form as WidgetForm;
  6. use Illuminate\Support\Collection;
  7. class Tab
  8. {
  9. /**
  10. * @var Form|WidgetForm
  11. */
  12. protected $form;
  13. /**
  14. * @var Collection
  15. */
  16. protected $tabs;
  17. /**
  18. * @var int
  19. */
  20. protected $offset = 0;
  21. /**
  22. * @var int
  23. */
  24. protected $columnOffset = 0;
  25. /**
  26. * @var bool
  27. */
  28. public $hasRows = false;
  29. /**
  30. * Tab constructor.
  31. *
  32. * @param Form|WidgetForm $form
  33. */
  34. public function __construct($form)
  35. {
  36. $this->form = $form;
  37. $this->tabs = new Collection();
  38. }
  39. /**
  40. * Append a tab section.
  41. *
  42. * @param string $title
  43. * @param \Closure $content
  44. * @param bool $active
  45. * @param string $id
  46. *
  47. * @return $this
  48. */
  49. public function append($title, \Closure $content, bool $active = false, ?string $id = null)
  50. {
  51. call_user_func($content, $this->form);
  52. $fields = $this->collectFields();
  53. $layout = $this->collectColumnLayout();
  54. $id = $id ?: ('tab-form-'.($this->tabs->count() + 1).'-'.mt_rand(0, 9999));
  55. $this->tabs->push(compact('id', 'title', 'fields', 'active', 'layout'));
  56. return $this;
  57. }
  58. /**
  59. * Collect fields under current tab.
  60. *
  61. * @return Collection
  62. */
  63. protected function collectFields()
  64. {
  65. $fields = clone $this->form->fields();
  66. $all = $fields->toArray();
  67. foreach ($this->form->rows() as $row) {
  68. $rowFields = $row->fields()->map(function ($field) {
  69. return $field['element'];
  70. });
  71. $match = false;
  72. foreach ($rowFields as $field) {
  73. if (($index = array_search($field, $all)) !== false) {
  74. if (! $match) {
  75. $fields->put($index, $row);
  76. } else {
  77. $fields->pull($index);
  78. }
  79. $match = true;
  80. }
  81. }
  82. $this->hasRows = true;
  83. }
  84. $fields = $fields->slice($this->offset);
  85. $this->offset += $fields->count();
  86. return $fields;
  87. }
  88. protected function collectColumnLayout()
  89. {
  90. $layout = clone $this->form->layout();
  91. $this->form->layout()->reset();
  92. return $layout;
  93. }
  94. /**
  95. * Set true for some one tab by title or id.
  96. *
  97. * @param string $value
  98. * @param string $field
  99. */
  100. public function active(string $value, string $field = 'title')
  101. {
  102. if ($this->tabs->where($field, $value)->isNotEmpty()) {
  103. $this->tabs = $this->tabs->map(function ($item) use ($value, $field) {
  104. $item['active'] = $item[$field] === $value;
  105. return $item;
  106. });
  107. }
  108. }
  109. /**
  110. * Set true for some one tab by key.
  111. *
  112. * @param int $index
  113. */
  114. public function activeByIndex(int $index = 0)
  115. {
  116. if ($this->tabs->offsetExists($index)) {
  117. $this->tabs = $this->tabs->map(function ($item, $itemKey) use ($index) {
  118. $item['active'] = $itemKey === $index;
  119. return $item;
  120. });
  121. }
  122. }
  123. /**
  124. * Get all tabs.
  125. *
  126. * @return Collection
  127. */
  128. public function getTabs()
  129. {
  130. // If there is no active tab, then active the first.
  131. if ($this->tabs->filter(function ($tab) {
  132. return $tab['active'];
  133. })->isEmpty()) {
  134. $first = $this->tabs->first();
  135. $first['active'] = true;
  136. $this->tabs->offsetSet(0, $first);
  137. }
  138. return $this->tabs;
  139. }
  140. /**
  141. * @return bool
  142. */
  143. public function isEmpty()
  144. {
  145. return $this->tabs->isEmpty();
  146. }
  147. /**
  148. * @return void
  149. */
  150. public function addScript()
  151. {
  152. $elementId = $this->form->getElementId();
  153. $script = <<<JS
  154. (function () {
  155. var hash = document.location.hash;
  156. if (hash) {
  157. $('#$elementId .nav-tabs a[href="' + hash + '"]').tab('show');
  158. }
  159. // Change hash for page-reload
  160. $('#$elementId .nav-tabs a').on('shown.bs.tab', function (e) {
  161. history.pushState(null,null, e.target.hash);
  162. });
  163. if ($('#$elementId .has-error').length) {
  164. $('#$elementId .has-error').each(function () {
  165. var tabId = '#'+$(this).closest('.tab-pane').attr('id');
  166. $('li a[href="'+tabId+'"] i').removeClass('hide');
  167. });
  168. var first = $('#$elementId .has-error:first').closest('.tab-pane').attr('id');
  169. $('li a[href="#'+first+'"]').tab('show');
  170. }
  171. })();
  172. JS;
  173. Admin::script($script);
  174. }
  175. }