Tree.php 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383
  1. <?php
  2. namespace Encore\Admin;
  3. use Closure;
  4. use Encore\Admin\Tree\Tools;
  5. use Illuminate\Contracts\Support\Renderable;
  6. use Illuminate\Database\Eloquent\Model;
  7. class Tree implements Renderable
  8. {
  9. /**
  10. * @var array
  11. */
  12. protected $items = [];
  13. /**
  14. * @var string
  15. */
  16. protected $elementId = 'tree-';
  17. /**
  18. * @var Model
  19. */
  20. protected $model;
  21. /**
  22. * @var \Closure
  23. */
  24. protected $queryCallback;
  25. /**
  26. * View of tree to render.
  27. *
  28. * @var string
  29. */
  30. protected $view = [
  31. 'tree' => 'admin::tree',
  32. 'branch' => 'admin::tree.branch',
  33. ];
  34. /**
  35. * @var \Closure
  36. */
  37. protected $callback;
  38. /**
  39. * @var null
  40. */
  41. protected $branchCallback = null;
  42. /**
  43. * @var bool
  44. */
  45. public $useCreate = true;
  46. /**
  47. * @var bool
  48. */
  49. public $useSave = true;
  50. /**
  51. * @var bool
  52. */
  53. public $useRefresh = true;
  54. /**
  55. * @var array
  56. */
  57. protected $nestableOptions = [];
  58. /**
  59. * Header tools.
  60. *
  61. * @var Tools
  62. */
  63. public $tools;
  64. /**
  65. * Menu constructor.
  66. *
  67. * @param Model|null $model
  68. */
  69. public function __construct(Model $model = null, \Closure $callback = null)
  70. {
  71. $this->model = $model;
  72. $this->path = app('request')->getPathInfo();
  73. $this->elementId .= uniqid();
  74. $this->setupTools();
  75. if ($callback instanceof \Closure) {
  76. call_user_func($callback, $this);
  77. }
  78. $this->initBranchCallback();
  79. }
  80. /**
  81. * Setup tree tools.
  82. */
  83. public function setupTools()
  84. {
  85. $this->tools = new Tools($this);
  86. }
  87. /**
  88. * Initialize branch callback.
  89. *
  90. * @return void
  91. */
  92. protected function initBranchCallback()
  93. {
  94. if (is_null($this->branchCallback)) {
  95. $this->branchCallback = function ($branch) {
  96. $key = $branch[$this->model->getKeyName()];
  97. $title = $branch[$this->model->getTitleColumn()];
  98. return "$key - $title";
  99. };
  100. }
  101. }
  102. /**
  103. * Set branch callback.
  104. *
  105. * @param \Closure $branchCallback
  106. *
  107. * @return $this
  108. */
  109. public function branch(\Closure $branchCallback)
  110. {
  111. $this->branchCallback = $branchCallback;
  112. return $this;
  113. }
  114. /**
  115. * Set query callback this tree.
  116. *
  117. * @return Model
  118. */
  119. public function query(\Closure $callback)
  120. {
  121. $this->queryCallback = $callback;
  122. return $this;
  123. }
  124. /**
  125. * Set nestable options.
  126. *
  127. * @param array $options
  128. *
  129. * @return $this
  130. */
  131. public function nestable($options = [])
  132. {
  133. $this->nestableOptions = array_merge($this->nestableOptions, $options);
  134. return $this;
  135. }
  136. /**
  137. * Disable create.
  138. *
  139. * @return void
  140. */
  141. public function disableCreate()
  142. {
  143. $this->useCreate = false;
  144. }
  145. /**
  146. * Disable save.
  147. *
  148. * @return void
  149. */
  150. public function disableSave()
  151. {
  152. $this->useSave = false;
  153. }
  154. /**
  155. * Disable refresh.
  156. *
  157. * @return void
  158. */
  159. public function disableRefresh()
  160. {
  161. $this->useRefresh = false;
  162. }
  163. /**
  164. * Save tree order from a input.
  165. *
  166. * @param string $serialize
  167. *
  168. * @return bool
  169. */
  170. public function saveOrder($serialize)
  171. {
  172. $tree = json_decode($serialize, true);
  173. if (json_last_error() != JSON_ERROR_NONE) {
  174. throw new \InvalidArgumentException(json_last_error_msg());
  175. }
  176. $this->model->saveOrder($tree);
  177. return true;
  178. }
  179. /**
  180. * Build tree grid scripts.
  181. *
  182. * @return string
  183. */
  184. protected function script()
  185. {
  186. $deleteConfirm = trans('admin.delete_confirm');
  187. $saveSucceeded = trans('admin.save_succeeded');
  188. $refreshSucceeded = trans('admin.refresh_succeeded');
  189. $deleteSucceeded = trans('admin.delete_succeeded');
  190. $confirm = trans('admin.confirm');
  191. $cancel = trans('admin.cancel');
  192. $nestableOptions = json_encode($this->nestableOptions);
  193. return <<<SCRIPT
  194. $('#{$this->elementId}').nestable($nestableOptions);
  195. $('.tree_branch_delete').click(function() {
  196. var id = $(this).data('id');
  197. swal({
  198. title: "$deleteConfirm",
  199. type: "warning",
  200. showCancelButton: true,
  201. confirmButtonColor: "#DD6B55",
  202. confirmButtonText: "$confirm",
  203. showLoaderOnConfirm: true,
  204. cancelButtonText: "$cancel",
  205. preConfirm: function() {
  206. return new Promise(function(resolve) {
  207. $.ajax({
  208. method: 'post',
  209. url: '{$this->path}/' + id,
  210. data: {
  211. _method:'delete',
  212. _token:LA.token,
  213. },
  214. success: function (data) {
  215. $.pjax.reload('#pjax-container');
  216. toastr.success('{$deleteSucceeded}');
  217. resolve(data);
  218. }
  219. });
  220. });
  221. }
  222. }).then(function(result) {
  223. var data = result.value;
  224. if (typeof data === 'object') {
  225. if (data.status) {
  226. swal(data.message, '', 'success');
  227. } else {
  228. swal(data.message, '', 'error');
  229. }
  230. }
  231. });
  232. });
  233. $('.{$this->elementId}-save').click(function () {
  234. var serialize = $('#{$this->elementId}').nestable('serialize');
  235. $.post('{$this->path}', {
  236. _token: LA.token,
  237. _order: JSON.stringify(serialize)
  238. },
  239. function(data){
  240. $.pjax.reload('#pjax-container');
  241. toastr.success('{$saveSucceeded}');
  242. });
  243. });
  244. $('.{$this->elementId}-refresh').click(function () {
  245. $.pjax.reload('#pjax-container');
  246. toastr.success('{$refreshSucceeded}');
  247. });
  248. $('.{$this->elementId}-tree-tools').on('click', function(e){
  249. var action = $(this).data('action');
  250. if (action === 'expand') {
  251. $('.dd').nestable('expandAll');
  252. }
  253. if (action === 'collapse') {
  254. $('.dd').nestable('collapseAll');
  255. }
  256. });
  257. SCRIPT;
  258. }
  259. /**
  260. * Set view of tree.
  261. *
  262. * @param string $view
  263. */
  264. public function setView($view)
  265. {
  266. $this->view = $view;
  267. }
  268. /**
  269. * Return all items of the tree.
  270. *
  271. * @param array $items
  272. */
  273. public function getItems()
  274. {
  275. return $this->model->withQuery($this->queryCallback)->toTree();
  276. }
  277. /**
  278. * Variables in tree template.
  279. *
  280. * @return array
  281. */
  282. public function variables()
  283. {
  284. return [
  285. 'id' => $this->elementId,
  286. 'tools' => $this->tools->render(),
  287. 'items' => $this->getItems(),
  288. 'useCreate' => $this->useCreate,
  289. 'useSave' => $this->useSave,
  290. 'useRefresh' => $this->useRefresh,
  291. ];
  292. }
  293. /**
  294. * Setup grid tools.
  295. *
  296. * @param Closure $callback
  297. *
  298. * @return void
  299. */
  300. public function tools(Closure $callback)
  301. {
  302. call_user_func($callback, $this->tools);
  303. }
  304. /**
  305. * Render a tree.
  306. *
  307. * @return \Illuminate\Http\JsonResponse|string
  308. */
  309. public function render()
  310. {
  311. Admin::script($this->script());
  312. view()->share([
  313. 'path' => $this->path,
  314. 'keyName' => $this->model->getKeyName(),
  315. 'branchView' => $this->view['branch'],
  316. 'branchCallback' => $this->branchCallback,
  317. ]);
  318. return view($this->view['tree'], $this->variables())->render();
  319. }
  320. /**
  321. * Get the string contents of the grid view.
  322. *
  323. * @return string
  324. */
  325. public function __toString()
  326. {
  327. return $this->render();
  328. }
  329. }