Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions config/menu.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,20 @@

'enabled' => env('MENU_MIDDLEWARE_ENABLED', true),

/*
|--------------------------------------------------------------------------
| Menu Item Sorting
|--------------------------------------------------------------------------
|
| This option controls the default sorting direction of menu items.
| Supported values are:
|
| - 'asc' : Sort menu items in ascending order
| - 'desc' : Sort menu items in descending order
|
*/
'order_by' => 'asc',

/*
|--------------------------------------------------------------------------
| Include Route List
Expand Down
1 change: 1 addition & 0 deletions resources/lang/en/menus.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
'icon' => 'Icon',
'class' => 'Class',
'attr' => 'Attributes',
'position' => 'Position',
'privilege' => 'Privilege',
'visible' => 'Status',
'visible_1' => 'Visible',
Expand Down
8 changes: 8 additions & 0 deletions resources/views/menus/form.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,14 @@ class="hide"></div>
</div>
</div>

<div class="form-group row">
{!! Form::label('position', __('menu-maker::menus.position'), ['class' => 'col-md-4 col-form-label text-md-right']) !!}
<div class="col-md-6">
{!! Form::number('position', null, ['class' => $errors->has('position') ? 'form-control is-invalid' : 'form-control', 'step' => '1']) !!}
{!! $errors->first('position', '<span class="invalid-feedback" role="alert"><strong>:message</strong></span>') !!}
</div>
</div>

<div class="form-group row required">
{!! Form::label('privilege', __('menu-maker::menus.privilege'), ['class' => 'col-md-4 col-form-label text-md-right']) !!}
<div class="col-md-6">
Expand Down
36 changes: 23 additions & 13 deletions resources/views/menus/tree.blade.php
Original file line number Diff line number Diff line change
@@ -1,21 +1,31 @@
<?php
$traverse = function ($menus) use (&$traverse, $selected) {
foreach ($menus as $menu) {
echo $menu->ancestors->count() ? '<ul>' : '';
echo '<li> ';
if (! $menu->children->count()) {
$checked = '';
if (in_array($menu->id, $selected)) {
$checked = 'checked';
}
echo '<div class="form-check"> <input class="form-check-input" ' . $checked . ' name="menu_ids[]" type="checkbox" value="' . $menu->id . '" id="menu-' . $menu->id . '">';
echo '<li data-id="' . $menu->id . '" class="mb-2">';
echo '<div class="d-flex justify-content-between align-items-center">';

$checked = '';
if (in_array($menu->id, $selected)) {
$checked = 'checked';
}

echo '<div class="form-check">';
echo '<input class="form-check-input" ' . $checked . ' name="menu_ids[]" type="checkbox" value="' . $menu->id . '" id="menu-' . $menu->id . '">';
echo '<label class="form-check-label" for="menu-' . $menu->id . '">' . $menu->name . '</label>';
echo $menu->children->count() ? '' : '</div>';
$traverse($menu->children);
echo '</div>';

echo '<span class="handle mr-2" style="cursor: move;">&#9776;</span>';
echo '</div>';

echo '<ul class="sortable-tree">';
if ($menu->children->isNotEmpty()) {
$traverse($menu->children);
}
echo '</ul>';
echo '</li>';
echo $menu->ancestors->count() ? '</ul>' : '';
}
};

$traverse($tree);
?>
<ul class="sortable-tree">
<?php $traverse($tree); ?>
</ul>
53 changes: 53 additions & 0 deletions resources/views/roles/menus.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
</div>
</div>
<div id="menu-tree"></div>
<input type="hidden" name="menu_order" id="menu_order">
<div class="form-group row mb-0">
<div class="col-md-6 offset-md-4">
{!! Form::submit(__('menu-maker::buttons.update'), ['class' => 'btn btn-primary']) !!}
Expand All @@ -62,17 +63,46 @@
</div>
<!-- /.row -->
</div>
<style>
.sortable-tree {
padding-left: 2.5rem;
list-style: none;
min-height: 5px;
}

.sortable-tree:empty {
padding-bottom: 25px;
}

#menu-tree>.sortable-tree {
padding-left: 0;
}
</style>
@endsection
@push('scripts')
<script src="https://cdn.jsdelivr.net/npm/sortablejs@1.15.6/Sortable.min.js"></script>
<script>
$(function () {
function initSortable() {
$('.sortable-tree').each(function () {
new Sortable(this, {
group: 'nested',
handle: '.handle',
animation: 150,
fallbackOnBody: true,
swapThreshold: 0.65
});
});
}

$('#section_id').on('change', function (e) {
var menu_id = $(this).val() || 0,
role_id = $('#role_id').val() || 0;
$('#menu-tree').html('');
if (menu_id > 0) {
$.get(baseUrl() + 'menus/' + menu_id + '/tree?g=' + role_id, function (data, status) {
$('#menu-tree').html(data);
initSortable();
}).fail(function (xhr, status, error) {
alert("An AJAX error occured: " + status + "\nError: " + error);
});
Expand All @@ -95,6 +125,29 @@
});

$('#section_id').trigger('change');

$('form').on('submit', function () {
var order = [];
function buildOrder(list) {
var items = [];
$(list).children('li').each(function () {
var id = $(this).data('id');
var children = [];
var subList = $(this).find('> ul');
if (subList.length) {
children = buildOrder(subList);
}
items.push({ id: id, children: children });
});
return items;
}

var rootList = $('#menu-tree').find('> ul');
if (rootList.length) {
order = buildOrder(rootList);
}
$('#menu_order').val(JSON.stringify(order));
});
});
</script>
@endpush
22 changes: 14 additions & 8 deletions src/Http/Controllers/MenuController.php
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ public function create()
public function store(Request $request)
{
$data = $request->only([
'name', 'alias', 'link', 'icon', 'class', 'attr', 'privilege', 'visible'
'name', 'alias', 'link', 'icon', 'class', 'attr', 'privilege', 'visible', 'position'
]);
$data['routes'] = $request->route_list;
$data['parent_id'] = Menu::findParent();
Expand Down Expand Up @@ -113,7 +113,7 @@ public function edit(Menu $menu)
public function update(Request $request, Menu $menu)
{
$data = $request->only([
'name', 'alias', 'link', 'icon', 'class', 'attr', 'privilege', 'visible'
'name', 'alias', 'link', 'icon', 'class', 'attr', 'privilege', 'visible', 'position'
]);
$data['routes'] = $request->route_list;
$data['parent_id'] = Menu::findParent();
Expand Down Expand Up @@ -155,13 +155,17 @@ public function destroy(Menu $menu)
*/
public function tree(Menu $node)
{
$tree = Menu::descendantsOf($node)
$tree = Menu::whereDescendantOf($node)
->where('privilege', 'PROTECTED')
->orderBy('position', config('menu.order_by', 'asc'))
->get()
->toTree($node);
$selected = [];
if(request()->has('g') && request('g') > 0)
{
$selected = Role::findOrFail(request('g'))->menus()->descendantsOf($node)->pluck('id')->toArray();
if (request()->has('g') && request('g') > 0) {
$selected = \DB::table('pcmm_menu_role')
->where('role_id', request('g'))
->pluck('menu_id')
->toArray();
}
return view('menu-maker::menus.tree', compact('tree', 'selected'));
}
Expand All @@ -170,8 +174,10 @@ public function selected() {

if (request()->ajax()) {
$group_id = request('g');
$parent_id = request('p');
$selected = Role::findOrFail($group_id)->menus()->descendantsOf($parent_id)->pluck('id')->toArray();
$selected = \DB::table('pcmm_menu_role')
->where('role_id', $group_id)
->pluck('menu_id')
->toArray();
return response()->json(compact('selected'), 200);
}
return response()->json([
Expand Down
21 changes: 21 additions & 0 deletions src/Http/Controllers/RoleController.php
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,27 @@ public function assign(MenuRoleRequest $request)
}
$role->menus()->attach($request->menu_ids);

// Update menu order if provided
if ($request->has('menu_order')) {
$order = json_decode($request->menu_order, true);
if (is_array($order)) {
$updatePosition = function ($items, $parentId) use (&$updatePosition) {
foreach ($items as $index => $item) {
$menu = Menu::find($item['id']);
if ($menu) {
$menu->position = $index;
$menu->parent_id = $parentId;
$menu->save();
}
if (!empty($item['children'])) {
$updatePosition($item['children'], $item['id']);
}
}
};
$updatePosition($order, $request->section_id);
}
}

$role->users->each(function ($user) {
RemoveUserMenuCache::dispatch($user);
});
Expand Down
6 changes: 4 additions & 2 deletions src/MenuMaker.php
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,8 @@ private function getAdminMenuItems()
{
$this->section->load([
'descendants' => function ($query) {
$query->visible();
$query->visible()
->orderBy('position', config('menu.order_by', 'asc'));
}
]);

Expand Down Expand Up @@ -97,7 +98,8 @@ private function getUserMenuItems()
->where('pcmm_roles.is_active', true)
->where($this->getTable() . '.id', $this->id);
});
});
})
->orderBy('position', config('menu.order_by', 'asc'));
}
]);

Expand Down