├── .gitignore ├── README.md ├── composer.json ├── composer.lock ├── images └── tree.png ├── resources ├── dist │ ├── jquery.nestable.min.css │ └── jquery.nestable.min.js ├── lang │ ├── ar │ │ └── filament-tree.php │ └── en │ │ └── filament-tree.php └── views │ ├── components │ ├── tree-field.blade.php │ └── tree-item.blade.php │ ├── tree-assets.blade.php │ └── tree-page.blade.php └── src ├── FilamentTreeServiceProvider.php ├── Forms └── Components │ └── TreeField.php ├── HasTree.php └── TreePage.php /.gitignore: -------------------------------------------------------------------------------- 1 | /vendor/ 2 | /.idea 3 | 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Filament Tree 2 | 3 |
4 | 5 |
6 |
7 | 8 | 9 | ```sh 10 | composer require yemenpoint/filament-tree 11 | ``` 12 | 13 | publish assets 14 | 15 | ```sh 16 | php artisan vendor:publish --tag="filament-tree-assets" 17 | php artisan vendor:publish --tag="filament-tree-views" 18 | ``` 19 | 20 | # Tree Field 21 | 22 | ### migration 23 | ```php 24 | Schema::table('tryings', function (Blueprint $table) { 25 | $table->json("items")->nullable(); 26 | }); 27 | ``` 28 | 29 | ```php 30 | 31 | use Yemenpoint\FilamentTree\Forms\Components\TreeField; 32 | 33 | TreeField::make("items") 34 | ->setMaxDepth(999) 35 | ->default([["id" => "1", "name" => "item 1", "children" => [["id" => "2", "name" => "item 2", "children" => []]]]]), 36 | ``` 37 | 38 | # Tree Page 39 | 40 | ## Table structure and model 41 | ```structure 42 | categories 43 | id - integer 44 | parent_id - integer 45 | order - integer 46 | name - string 47 | ``` 48 | ```php 49 | Schema::create('categories', function (Blueprint $table) { 50 | $table->id(); 51 | $table->unsignedBigInteger('parent_id')->nullable(); 52 | $table->integer('order')->nullable()->default(0); 53 | $table->string('name'); 54 | }); 55 | ``` 56 | 57 | # model 58 | ```php 59 | hasMany(self::class, 'parent_id', 'id')->with("children")->orderBy("order"); 74 | } 75 | } 76 | 77 | ``` 78 | # page 79 | 80 | ```php 81 | 82 | whereNull("parent_id")->orderBy("order")->get()->toArray(); 97 | } 98 | 99 | public function getMaxDepth(): int 100 | { 101 | return parent::getMaxDepth(); // TODO: Change the autogenerated stub 102 | } 103 | 104 | public function isDisabled(): bool 105 | { 106 | return parent::isDisabled(); // TODO: Change the autogenerated stub 107 | } 108 | 109 | } 110 | 111 | ``` -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "yemenpoint/filament-tree", 3 | "description": "Filament Tree field and page", 4 | "type": "library", 5 | "require": { 6 | "php": "^8.0", 7 | "filament/filament": "*" 8 | }, 9 | "autoload": { 10 | "psr-4": { 11 | "Yemenpoint\\FilamentTree\\": "src/" 12 | } 13 | }, 14 | "authors": [ 15 | { 16 | "name": "yemenpoint", 17 | "email": "ebrahim29001@gmail.com" 18 | } 19 | ], 20 | "extra": { 21 | "laravel": { 22 | "providers": [ 23 | "Yemenpoint\\FilamentTree\\FilamentTreeServiceProvider" 24 | ] 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /images/tree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yemenpoint/FilamentTree/8cd175a7abfa317f2eed14c79c8694293ded9de8/images/tree.png -------------------------------------------------------------------------------- /resources/dist/jquery.nestable.min.css: -------------------------------------------------------------------------------- 1 | .dd{position:relative;display:block;margin:0;padding:0;max-width:600px;list-style:none;font-size:13px;line-height:20px}.dd-list{display:block;position:relative;margin:0;padding:0;list-style:none}.dd-list .dd-list{padding-left:30px}.dd-empty,.dd-item,.dd-placeholder{display:block;position:relative;margin:0;padding:0;min-height:20px;font-size:13px;line-height:20px}.dd-handle{display:block;height:30px;margin:5px 0;padding:5px 10px;color:#333;text-decoration:none;font-weight:700;border:1px solid #ccc;background:#fafafa;border-radius:3px;box-sizing:border-box}.dd-handle:hover{color:#2ea8e5;background:#fff}.dd-item>button{position:relative;cursor:pointer;float:left;width:25px;height:20px;margin:5px 0;padding:0;text-indent:100%;white-space:nowrap;overflow:hidden;border:0;background:0 0;font-size:12px;line-height:1;text-align:center;font-weight:700}.dd-item>button:before{display:block;position:absolute;width:100%;text-align:center;text-indent:0}.dd-item>button.dd-expand:before{content:'+'}.dd-item>button.dd-collapse:before{content:'-'}.dd-expand{display:none}.dd-collapsed .dd-collapse,.dd-collapsed .dd-list{display:none}.dd-collapsed .dd-expand{display:block}.dd-empty,.dd-placeholder{margin:5px 0;padding:0;min-height:30px;background:#f2fbff;border:1px dashed #b6bcbf;box-sizing:border-box;-moz-box-sizing:border-box}.dd-empty{border:1px dashed #bbb;min-height:100px;background-color:#e5e5e5;background-size:60px 60px;background-position:0 0,30px 30px}.dd-dragel{position:absolute;pointer-events:none;z-index:9999}.dd-dragel>.dd-item .dd-handle{margin-top:0}.dd-dragel .dd-handle{box-shadow:2px 4px 6px 0 rgba(0,0,0,.1)}.dd-nochildren .dd-placeholder{display:none} -------------------------------------------------------------------------------- /resources/dist/jquery.nestable.min.js: -------------------------------------------------------------------------------- 1 | !function(t,e,s,i){function o(e,o){this.w=t(s),this.el=t(e),(o=o||a).rootClass!==i&&"dd"!==o.rootClass&&(o.listClass=o.listClass?o.listClass:o.rootClass+"-list",o.itemClass=o.itemClass?o.itemClass:o.rootClass+"-item",o.dragClass=o.dragClass?o.dragClass:o.rootClass+"-dragel",o.handleClass=o.handleClass?o.handleClass:o.rootClass+"-handle",o.collapsedClass=o.collapsedClass?o.collapsedClass:o.rootClass+"-collapsed",o.placeClass=o.placeClass?o.placeClass:o.rootClass+"-placeholder",o.noDragClass=o.noDragClass?o.noDragClass:o.rootClass+"-nodrag",o.noChildrenClass=o.noChildrenClass?o.noChildrenClass:o.rootClass+"-nochildren",o.emptyClass=o.emptyClass?o.emptyClass:o.rootClass+"-empty"),this.options=t.extend({},a,o),this.options.json!==i&&this._build(),this.init()}var n="ontouchstart"in s,l=function(){var t=s.createElement("div"),i=s.documentElement;if(!("pointerEvents"in t.style))return!1;t.style.pointerEvents="auto",t.style.pointerEvents="x",i.appendChild(t);var o=e.getComputedStyle&&"auto"===e.getComputedStyle(t,"").pointerEvents;return i.removeChild(t),!!o}(),a={contentCallback:function(t){return t.content?t.content:t.id},listNodeName:"ol",itemNodeName:"li",handleNodeName:"div",contentNodeName:"span",rootClass:"dd",listClass:"dd-list",itemClass:"dd-item",dragClass:"dd-dragel",handleClass:"dd-handle",contentClass:"dd-content",collapsedClass:"dd-collapsed",placeClass:"dd-placeholder",noDragClass:"dd-nodrag",noChildrenClass:"dd-nochildren",emptyClass:"dd-empty",expandBtnHTML:'',collapseBtnHTML:'',group:0,maxDepth:5,threshold:20,fixedDepth:!1,fixed:!1,includeContent:!1,scroll:!1,scrollSensitivity:1,scrollSpeed:5,scrollTriggers:{top:40,left:40,right:-40,bottom:-40},effect:{animation:"none",time:"slow"},callback:function(t,e,s){},onDragStart:function(t,e,s){},beforeDragStop:function(t,e,s){},listRenderer:function(t,e){var s="<"+e.listNodeName+' class="'+e.listClass+'">';return s+=t,s+=""},itemRenderer:function(e,s,i,o,n){var l=t.map(e,function(t,e){return" "+e+'="'+t+'"'}).join(" "),a="<"+o.itemNodeName+l+">";return a+="<"+o.handleNodeName+' class="'+o.handleClass+'">',a+="<"+o.contentNodeName+' class="'+o.contentClass+'">',a+=s,a+="",a+="",a+=i,a+=""}};o.prototype={init:function(){var s=this;s.reset(),s.el.data("nestable-group",this.options.group),s.placeEl=t('
');var i=this.el.find(s.options.itemNodeName);t.each(i,function(e,i){var o=t(i),n=o.parent();s.setParent(o),n.hasClass(s.options.collapsedClass)&&s.collapseItem(n.parent())}),i.length||this.appendEmptyElement(this.el),s.el.on("click","button",function(e){if(!s.dragEl){var i=t(e.currentTarget),o=i.data("action"),n=i.parents(s.options.itemNodeName).eq(0);"collapse"===o&&s.collapseItem(n),"expand"===o&&s.expandItem(n)}});var o=function(e){var i=t(e.target);if(!i.hasClass(s.options.handleClass)){if(i.closest("."+s.options.noDragClass).length)return;i=i.closest("."+s.options.handleClass)}i.length&&!s.dragEl&&(s.isTouch=/^touch/.test(e.type),s.isTouch&&1!==e.touches.length||(e.preventDefault(),s.dragStart(e.touches?e.touches[0]:e)))},l=function(t){s.dragEl&&(t.preventDefault(),s.dragMove(t.touches?t.touches[0]:t))},a=function(t){s.dragEl&&(t.preventDefault(),s.dragStop(t.touches?t.changedTouches[0]:t))};n&&(s.el[0].addEventListener("touchstart",o,!1),e.addEventListener("touchmove",l,!1),e.addEventListener("touchend",a,!1),e.addEventListener("touchcancel",a,!1)),s.el.on("mousedown",o),s.w.on("mousemove",l),s.w.on("mouseup",a);s.el.bind("destroy-nestable",function(){n&&(s.el[0].removeEventListener("touchstart",o,!1),e.removeEventListener("touchmove",l,!1),e.removeEventListener("touchend",a,!1),e.removeEventListener("touchcancel",a,!1)),s.el.off("mousedown",o),s.w.off("mousemove",l),s.w.off("mouseup",a),s.el.off("click"),s.el.unbind("destroy-nestable"),s.el.data("nestable",null)})},destroy:function(){this.el.trigger("destroy-nestable")},add:function(e){var s="."+this.options.listClass,o=t(this.el).children(s);e.parent_id!==i&&(o=o.find('[data-id="'+e.parent_id+'"]'),delete e.parent_id,0===o.children(s).length&&(o=o.append(this.options.listRenderer("",this.options))),o=o.find(s+":first"),this.setParent(o.parent())),o.append(this._buildItem(e,this.options))},replace:function(t){var e=this._buildItem(t,this.options);this._getItemById(t.id).replaceWith(e)},removeItem:function(e){var s=this.options,i=this.el;(e=e||this).remove();var o="."+s.listClass+" ."+s.listClass+":not(:has(*))";t(i).find(o).remove();t(i).find('[data-action="expand"], [data-action="collapse"]').each(function(){0===t(this).siblings("."+s.listClass).length&&t(this).remove()})},remove:function(t,e){var s=this.options,i=this,o=this._getItemById(t),n=s.effect.animation||"fade",l=s.effect.time||"slow";"fade"===n?o.fadeOut(l,function(){i.removeItem(o)}):this.removeItem(o),e&&e()},removeAll:function(e){function s(){l.each(function(){i.removeItem(t(this))}),n.show(),e&&e()}var i=this,o=this.options,n=i.el.find(o.listNodeName).first(),l=n.children(o.itemNodeName),a=o.effect.animation||"fade",r=o.effect.time||"slow";"fade"===a?n.fadeOut(r,s):s()},_getItemById:function(e){return t(this.el).children("."+this.options.listClass).find('[data-id="'+e+'"]')},_build:function(){var e=this.options.json;"string"==typeof e&&(e=JSON.parse(e)),t(this.el).html(this._buildList(e,this.options))},_buildList:function(e,s){if(!e)return"";var i="",o=this;return t.each(e,function(t,e){i+=o._buildItem(e,s)}),s.listRenderer(i,s)},_buildItem:function(e,s){function i(t){var e={"&":"&","<":"<",">":">",'"':""","'":"'"};return t+"".replace(/[&<>"']/g,function(t){return e[t]})}function o(t){var e={};for(var s in t)e[t[s]]=t[s];return e}var n=function(e){delete(e=t.extend({},e)).children,delete e.classes,delete e.content;var s={};return t.each(e,function(t,e){"object"==typeof e&&(e=JSON.stringify(e)),s["data-"+t]=i(e)}),s}(e);n.class=function(e,s){var i=e.classes||{};"string"==typeof i&&(i=[i]);var n=o(i);return n[s.itemClass]=s.itemClass,t.map(n,function(t){return t}).join(" ")}(e,s);var l=s.contentCallback(e),a=this._buildList(e.children,s),r=t(s.itemRenderer(n,l,a,s,e));return this.setParent(r),r[0].outerHTML},serialize:function(){var e=this,s=function(i){var o=[];return i.children(e.options.itemNodeName).each(function(){var i=t(this),n=t.extend({},i.data()),l=i.children(e.options.listNodeName);if(e.options.includeContent){var a=i.find("."+e.options.contentClass).html();a&&(n.content=a)}l.length&&(n.children=s(l)),o.push(n)}),o};return s(e.el.find(e.options.listNodeName).first())},asNestedSet:function(){function e(i,l,a){var r,d,h=a+1;return t(i).children(o.listNodeName).children(o.itemNodeName).length>0&&(l++,t(i).children(o.listNodeName).children(o.itemNodeName).each(function(){h=e(t(this),l,h)}),l--),r=t(i).attr("data-id"),s(r)&&(r=parseInt(r)),d=t(i).parent(o.listNodeName).parent(o.itemNodeName).attr("data-id")||"",s(d)&&(d=parseInt(d)),r&&n.push({id:r,parent_id:d,depth:l,lft:a,rgt:h}),a=h+1}function s(e){return t.isNumeric(e)&&Math.floor(e)==e}var i=this,o=i.options,n=[],l=1;return i.el.find(o.listNodeName).first().children(o.itemNodeName).each(function(){l=e(this,0,l)}),n=n.sort(function(t,e){return t.lft-e.lft})},returnOptions:function(){return this.options},serialise:function(){return this.serialize()},toHierarchy:function(e){function s(e){var o=(t(e).attr(i.attribute||"id")||"").match(i.expression||/(.+)[-=_](.+)/);if(o){var n={id:o[2]};return t(e).children(i.listType).children(i.items).length>0&&(n.children=[],t(e).children(i.listType).children(i.items).each(function(){var t=s(this);n.children.push(t)})),n}}var i=t.extend({},this.options,e),o=[];return t(this.element).children(i.items).each(function(){var t=s(this);o.push(t)}),o},toArray:function(){function e(n,l,a){var r,d,h=a+1;return n.children(s.options.listNodeName).children(s.options.itemNodeName).length>0&&(l++,n.children(s.options.listNodeName).children(s.options.itemNodeName).each(function(){h=e(t(this),l,h)}),l--),r=n.data().id,d=l===i+1?s.rootID:n.parent(s.options.listNodeName).parent(s.options.itemNodeName).data().id,r&&o.push({id:r,parent_id:d,depth:l,left:a,right:h}),a=h+1}var s=t.extend({},this.options,this),i=s.startDepthCount||0,o=[],n=2,l=this;return l.el.find(l.options.listNodeName).first().children(l.options.itemNodeName).each(function(){n=e(t(this),i+1,n)}),o=o.sort(function(t,e){return t.left-e.left})},reset:function(){this.mouse={offsetX:0,offsetY:0,startX:0,startY:0,lastX:0,lastY:0,nowX:0,nowY:0,distX:0,distY:0,dirAx:0,dirX:0,dirY:0,lastDirX:0,lastDirY:0,distAxX:0,distAxY:0},this.isTouch=!1,this.moving=!1,this.dragEl=null,this.dragRootEl=null,this.dragDepth=0,this.hasNewRoot=!1,this.pointEl=null},expandItem:function(t){t.removeClass(this.options.collapsedClass)},collapseItem:function(t){t.children(this.options.listNodeName).length&&t.addClass(this.options.collapsedClass)},expandAll:function(){var e=this;e.el.find(e.options.itemNodeName).each(function(){e.expandItem(t(this))})},collapseAll:function(){var e=this;e.el.find(e.options.itemNodeName).each(function(){e.collapseItem(t(this))})},setParent:function(e){e.is(this.options.itemNodeName)&&e.children(this.options.listNodeName).length&&(e.children("[data-action]").remove(),e.prepend(t(this.options.expandBtnHTML)),e.prepend(t(this.options.collapseBtnHTML)))},unsetParent:function(t){t.removeClass(this.options.collapsedClass),t.children("[data-action]").remove(),t.children(this.options.listNodeName).remove()},dragStart:function(e){var i=this.mouse,o=t(e.target).closest(this.options.itemNodeName),n={top:e.pageY,left:e.pageX},l=this.options.onDragStart.call(this,this.el,o,n);if(void 0===l||!1!==l){this.placeEl.css("height",o.height()),i.offsetX=e.pageX-o.offset().left,i.offsetY=e.pageY-o.offset().top,i.startX=i.lastX=e.pageX,i.startY=i.lastY=e.pageY,this.dragRootEl=this.el,this.dragEl=t(s.createElement(this.options.listNodeName)).addClass(this.options.listClass+" "+this.options.dragClass),this.dragEl.css("width",o.outerWidth()),this.setIndexOfItem(o),o.after(this.placeEl),o[0].parentNode.removeChild(o[0]),o.appendTo(this.dragEl),t(s.body).append(this.dragEl),this.dragEl.css({left:e.pageX-i.offsetX,top:e.pageY-i.offsetY});var a,r,d=this.dragEl.find(this.options.itemNodeName);for(a=0;athis.dragDepth&&(this.dragDepth=r)}},createSubLevel:function(e,s){var i=t("<"+this.options.listNodeName+"/>").addClass(this.options.listClass);return s&&i.append(s),e.append(i),this.setParent(e),i},setIndexOfItem:function(e,s){(s=s||[]).unshift(e.index()),t(e[0].parentNode)[0]!==this.dragRootEl[0]?this.setIndexOfItem(t(e[0].parentNode),s):this.dragEl.data("indexOfItem",s)},restoreItemAtIndex:function(e,s){for(var i=this.el,o=s.length-1,n=0;n0?1:-1,d.dirY=0===d.distY?0:d.distY>0?1:-1;var h=Math.abs(d.distX)>Math.abs(d.distY)?1:0;if(!d.moving)return d.dirAx=h,void(d.moving=!0);if(r.scroll)if(void 0!==e.jQuery.fn.scrollParent){var c=!1,p=this.el.scrollParent()[0];p!==s&&"HTML"!==p.tagName?(r.scrollTriggers.bottom+p.offsetHeight-i.pageY=r.threshold&&(d.distAxX=0,a=this.placeEl.prev(r.itemNodeName),d.distX>0&&a.length&&!a.hasClass(r.collapsedClass)&&!a.hasClass(r.noChildrenClass)&&(o=a.find(r.listNodeName).last(),this.placeEl.parents(r.listNodeName).length+this.dragDepth<=r.maxDepth&&(o.length?(o=a.children(r.listNodeName).last()).append(this.placeEl):this.createSubLevel(a,this.placeEl))),d.distX<0&&(this.placeEl.next(r.itemNodeName).length||(n=this.placeEl.parent(),this.placeEl.closest(r.itemNodeName).after(this.placeEl),n.children().length||this.unsetParent(n.parent()))));var f=!1;if(l||(this.dragEl[0].style.visibility="hidden"),this.pointEl=t(s.elementFromPoint(i.pageX-s.body.scrollLeft,i.pageY-(e.pageYOffset||s.documentElement.scrollTop))),l||(this.dragEl[0].style.visibility="visible"),this.pointEl.hasClass(r.handleClass)&&(this.pointEl=this.pointEl.closest(r.itemNodeName)),this.pointEl.hasClass(r.emptyClass))f=!0;else if(!this.pointEl.length||!this.pointEl.hasClass(r.itemClass))return;var u=this.pointEl.closest("."+r.rootClass),m=this.dragRootEl.data("nestable-id")!==u.data("nestable-id");if(!d.dirAx||m||f){if(m&&r.group!==u.data("nestable-group"))return;if(this.options.fixedDepth&&this.dragDepth+1!==this.pointEl.parents(r.listNodeName).length)return;if(this.dragDepth-1+this.pointEl.parents(r.listNodeName).length>r.maxDepth)return;var g=i.pageY')}},t.fn.nestable=function(s){var i=this,n=this,l=arguments;return"Nestable"in e||(e.Nestable={},Nestable.counter=0),i.each(function(){var e=t(this).data("nestable");if(e){if("string"==typeof s&&"function"==typeof e[s])if(l.length>1){for(var i=[],a=1;a 'تم الحفظ بنجاح', 5 | 'tree_error_message' => 'حدث خطا اثناء الحفظ', 6 | 'collapse_all' => 'تصغير الكل', 7 | 'expand_all' => 'توسيع الكل', 8 | 'save' => 'حفظ', 9 | ]; -------------------------------------------------------------------------------- /resources/lang/en/filament-tree.php: -------------------------------------------------------------------------------- 1 | 'saved successfully', 5 | 'tree_error_message' => 'something went wrong', 6 | 'collapse_all' => 'collapse all', 7 | 'expand_all' => 'expand all', 8 | 'save' => 'save', 9 | ]; -------------------------------------------------------------------------------- /resources/views/components/tree-field.blade.php: -------------------------------------------------------------------------------- 1 | @php 2 | 3 | $tree_id = "tree" . \Illuminate\Support\Str::slug($getStatePath(), "_"); 4 | $items = $getValue(); 5 | @endphp 6 | 7 | @include("filament-tree::tree-assets") 8 | 9 | 38 | 48 |
51 | 52 | 53 | 58 | 63 | 64 | 65 |
66 |
    67 | @if($items && is_array($items)) 68 | @foreach ($items as $item) 69 | @include("filament-tree::components.tree-item", ["item"=> $item]) 70 | @endforeach 71 | @endif 72 |
73 |
74 | 75 | 76 |
77 |
78 | -------------------------------------------------------------------------------- /resources/views/components/tree-item.blade.php: -------------------------------------------------------------------------------- 1 |
  • 2 |
    {{data_get($item,"name")}}
    3 |
      4 | @if(count($children = data_get($item,"children",[]))) 5 | @foreach ($children as $child) 6 | @include("filament-tree::components.tree-item", ["item"=> $child]) 7 | @endforeach 8 | @endif 9 |
    10 |
  • 11 | -------------------------------------------------------------------------------- /resources/views/tree-assets.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /resources/views/tree-page.blade.php: -------------------------------------------------------------------------------- 1 | @php 2 | $tree_id = "tree_view_id"; 3 | @endphp 4 | 5 | @include("filament-tree::tree-assets") 6 | 34 | 35 | 36 | 37 | 42 | 47 | 48 | 49 |
    50 |
      51 | @if($items && is_array($items)) 52 | @foreach ($items as $item) 53 | @include("filament-tree::components.tree-item", ["item"=> $item]) 54 | @endforeach 55 | @endif 56 |
    57 |
    58 | @if(!$this->isDisabled()) 59 | 60 | 69 | @endif 70 | 71 |
    72 | -------------------------------------------------------------------------------- /src/FilamentTreeServiceProvider.php: -------------------------------------------------------------------------------- 1 | name('filament-tree') 15 | ->hasAssets() 16 | ->hasTranslations() 17 | ->hasViews(); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/Forms/Components/TreeField.php: -------------------------------------------------------------------------------- 1 | maxDepth; 16 | } 17 | 18 | 19 | public function setMaxDepth(int $maxDepth) 20 | { 21 | $this->maxDepth = $maxDepth; 22 | return $this; 23 | } 24 | 25 | 26 | public function getValue() 27 | { 28 | $state = parent::getState(); 29 | 30 | if (is_array($state)) { 31 | return $state; 32 | } else { 33 | try { 34 | return json_decode($state, true); 35 | } catch (\Exception $e) { 36 | return []; 37 | } 38 | } 39 | } 40 | 41 | public function getState() 42 | { 43 | $state = parent::getState(); 44 | 45 | if (is_array($state)) { 46 | return json_encode($state); 47 | } else { 48 | try { 49 | return $state; 50 | } catch (\Exception $e) { 51 | return json_encode([]); 52 | } 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/HasTree.php: -------------------------------------------------------------------------------- 1 | &$item) { 24 | $item[self::orderColumnName()] = $key; 25 | } 26 | foreach ($readyItems as $i) { 27 | self::where("id",data_get($i,"id"))->update($i); 28 | } 29 | 30 | return ["success", __("filament-tree::filament-tree.tree_saved_message")]; 31 | } 32 | 33 | 34 | public static function prepareNode(&$readyItems, $item, $parent_id = null) 35 | { 36 | $readyItems[] = [ 37 | "id" => data_get($item, 'id'), 38 | self::parentColumnName() => $parent_id, 39 | ]; 40 | 41 | if ($children = data_get($item, "children", [])) { 42 | foreach ($children as $child) { 43 | self::prepareNode($readyItems, $child, data_get($item, 'id')); 44 | } 45 | } 46 | } 47 | 48 | } -------------------------------------------------------------------------------- /src/TreePage.php: -------------------------------------------------------------------------------- 1 | $this->getItems() 30 | ]; 31 | } 32 | 33 | public function updateTree($tree) 34 | { 35 | if ($this->isDisabled()) { 36 | return; 37 | } 38 | try { 39 | $model = static::getModel(); 40 | 41 | list($status, $message) = $model::SaveTree($tree); 42 | 43 | if ($status && $message) { 44 | $this->notify($status, $message); 45 | } 46 | 47 | } catch (\Exception $e) { 48 | $this->notify("error", __("filament-tree::filament-tree.tree_error_message")); 49 | } 50 | } 51 | 52 | } 53 | --------------------------------------------------------------------------------