Modal.php 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404
  1. <?php
  2. namespace Dcat\Admin\Widgets;
  3. use Closure;
  4. use Dcat\Admin\Admin;
  5. use Dcat\Admin\Grid\LazyRenderable as LazyGrid;
  6. use Dcat\Admin\Contracts\LazyRenderable;
  7. use Dcat\Admin\Support\Helper;
  8. use Dcat\Admin\Traits\InteractsWithRenderApi;
  9. use Illuminate\Contracts\Support\Renderable;
  10. use Illuminate\Support\Str;
  11. class Modal extends Widget
  12. {
  13. use InteractsWithRenderApi;
  14. protected $target = 'modal';
  15. /**
  16. * @var string|Closure|Renderable
  17. */
  18. protected $title;
  19. /**
  20. * @var string|Closure|Renderable
  21. */
  22. protected $content;
  23. /**
  24. * @var string|Closure|Renderable
  25. */
  26. protected $footer;
  27. /**
  28. * @var string|Closure|Renderable
  29. */
  30. protected $button;
  31. /**
  32. * @var string
  33. */
  34. protected $size = '';
  35. /**
  36. * @var array
  37. */
  38. protected $events = [];
  39. /**
  40. * @var int
  41. */
  42. protected $delay = 10;
  43. /**
  44. * @var bool
  45. */
  46. protected $join = false;
  47. /**
  48. * Modal constructor.
  49. *
  50. * @param string|Closure|Renderable $title
  51. * @param string|Closure|Renderable|LazyRenderable $content
  52. */
  53. public function __construct($title = null, $content = null)
  54. {
  55. $this->id('modal-'.Str::random(8));
  56. $this->title($title);
  57. $this->content($content);
  58. $this->class('modal fade');
  59. }
  60. /**
  61. * 设置弹窗尺寸.
  62. *
  63. * @param string $size
  64. *
  65. * @return $this
  66. */
  67. public function size(string $size)
  68. {
  69. $this->size = $size;
  70. return $this;
  71. }
  72. /**
  73. * 设置弹窗尺寸为 sm 300px.
  74. *
  75. * @return $this
  76. */
  77. public function sm()
  78. {
  79. return $this->size('sm');
  80. }
  81. /**
  82. * 设置弹窗尺寸为 lg 800px.
  83. *
  84. * @return $this
  85. */
  86. public function lg()
  87. {
  88. return $this->size('lg');
  89. }
  90. /**
  91. * 设置弹窗尺寸为 xl 1140px.
  92. *
  93. * @return $this
  94. */
  95. public function xl()
  96. {
  97. return $this->size('xl');
  98. }
  99. /**
  100. * 设置loading效果延迟时间.
  101. *
  102. * @param int $delay
  103. *
  104. * @return $this
  105. */
  106. public function delay(int $delay)
  107. {
  108. $this->delay = $delay;
  109. return $this;
  110. }
  111. /**
  112. * 设置按钮.
  113. *
  114. * @param string|Closure|Renderable $button
  115. *
  116. * @return $this
  117. */
  118. public function button($button)
  119. {
  120. $this->button = $button;
  121. return $this;
  122. }
  123. /**
  124. * 设置弹窗标题.
  125. *
  126. * @param string|Closure|Renderable $title
  127. *
  128. * @return $this
  129. */
  130. public function title($title)
  131. {
  132. $this->title = $title;
  133. return $this;
  134. }
  135. /**
  136. * 设置弹窗内容.
  137. *
  138. * @param string|Closure|Renderable|LazyRenderable $content
  139. *
  140. * @return $this
  141. */
  142. public function content($content)
  143. {
  144. if ($content instanceof LazyGrid) {
  145. $content = $table =
  146. LazyTable::make()
  147. ->from($content)
  148. ->simple()
  149. ->load(false);
  150. $this->onShow($table->getLoadScript());
  151. }
  152. if ($content instanceof LazyRenderable) {
  153. $this->setRenderable($content);
  154. } else {
  155. $this->content = $content;
  156. }
  157. return $this;
  158. }
  159. /**
  160. * @param string|Closure|Renderable|LazyRenderable $content
  161. *
  162. * @return $this
  163. */
  164. public function body($content)
  165. {
  166. return $this->content($content);
  167. }
  168. /**
  169. * 设置是否返回弹窗HTML.
  170. *
  171. * @param bool $value
  172. *
  173. * @return $this
  174. */
  175. public function join(bool $value = true)
  176. {
  177. $this->join = $value;
  178. return $this;
  179. }
  180. /**
  181. * 设置弹窗底部内容.
  182. *
  183. * @param string|Closure|Renderable|LazyRenderable $footer
  184. *
  185. * @return $this
  186. */
  187. public function footer($footer)
  188. {
  189. $this->footer = $footer;
  190. return $this;
  191. }
  192. /**
  193. * 监听弹窗事件.
  194. *
  195. * @param string $event
  196. * @param string $script
  197. *
  198. * @return $this
  199. */
  200. public function on(string $event, string $script)
  201. {
  202. $this->events[] = compact('event', 'script');
  203. return $this;
  204. }
  205. /**
  206. * 监听弹窗显示事件.
  207. *
  208. * @param string $script
  209. *
  210. * @return $this
  211. */
  212. public function onShow(string $script)
  213. {
  214. return $this->on('show.bs.modal', $script);
  215. }
  216. /**
  217. * 监听弹窗已显示事件.
  218. *
  219. * @param string $script
  220. *
  221. * @return $this
  222. */
  223. public function onShown(string $script)
  224. {
  225. return $this->on('shown.bs.modal', $script);
  226. }
  227. /**
  228. * 监听弹窗隐藏事件.
  229. *
  230. * @param string $script
  231. *
  232. * @return $this
  233. */
  234. public function onHide(string $script)
  235. {
  236. return $this->on('hide.bs.modal', $script);
  237. }
  238. /**
  239. * 监听弹窗已隐藏事件.
  240. *
  241. * @param string $script
  242. *
  243. * @return $this
  244. */
  245. public function onHidden(string $script)
  246. {
  247. return $this->on('hidden.bs.modal', $script);
  248. }
  249. protected function addEventScript()
  250. {
  251. if (! $this->events) {
  252. return;
  253. }
  254. $script = '';
  255. foreach ($this->events as $v) {
  256. $script .= "target.on('{$v['event']}', function (event) {
  257. {$v['script']}
  258. });";
  259. }
  260. $this->script = <<<JS
  261. (function () {
  262. var target = $('{$this->getElementSelector()}'), body = target.find('.modal-body');
  263. {$this->getRenderableScript()}
  264. {$script}
  265. })();
  266. JS;
  267. }
  268. protected function addLoadRenderableScript()
  269. {
  270. if (! $this->getRenderable()) {
  271. return;
  272. }
  273. $this->on('show.bs.modal', <<<JS
  274. body.html('<div style="min-height:150px"></div>').loading();
  275. setTimeout(function () {
  276. target.trigger('{$this->target}:load')
  277. }, {$this->delay});
  278. JS
  279. );
  280. }
  281. /**
  282. * {@inheritDoc}
  283. */
  284. public function render()
  285. {
  286. $this->addLoadRenderableScript();
  287. $this->addEventScript();
  288. if ($this->join) {
  289. return $this->renderButton().parent::render();
  290. }
  291. Admin::html(parent::render());
  292. return $this->renderButton();
  293. }
  294. public function html()
  295. {
  296. return <<<HTML
  297. <div {$this->formatHtmlAttributes()} role="dialog">
  298. <div class="modal-dialog modal-{$this->size}">
  299. <div class="modal-content">
  300. <div class="modal-header">
  301. <h4 class="modal-title">{$this->renderTitle()}</h4>
  302. <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
  303. </div>
  304. <div class="modal-body">{$this->renderContent()}</div>
  305. {$this->renderFooter()}
  306. </div>
  307. </div>
  308. </div>
  309. HTML;
  310. }
  311. protected function renderTitle()
  312. {
  313. return Helper::render($this->title);
  314. }
  315. protected function renderContent()
  316. {
  317. return Helper::render($this->content);
  318. }
  319. protected function renderFooter()
  320. {
  321. $footer = Helper::render($this->footer);
  322. if (! $footer) {
  323. return;
  324. }
  325. return <<<HTML
  326. <div class="modal-footer">{$footer}</div>
  327. HTML;
  328. }
  329. protected function renderButton()
  330. {
  331. if (! $this->button) {
  332. return;
  333. }
  334. $button = Helper::render($this->button);
  335. // 如果没有HTML标签则添加一个 a 标签
  336. if (! preg_match('/(\<\/[\d\w]+\s*\>+)/i', $button)) {
  337. $button = "<a href=\"javascript:void(0)\">{$button}</a>";
  338. }
  339. return <<<HTML
  340. <span style="cursor: pointer" data-toggle="modal" data-target="#{$this->id()}">{$button}</span>
  341. HTML;
  342. }
  343. }