Modal.php 6.4 KB

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