Skip to content

Instantly share code, notes, and snippets.

@iamnasirudeen
Created September 21, 2019 20:28
Show Gist options
  • Save iamnasirudeen/65a2faffe5f08fac76d8d18eec4dfbe9 to your computer and use it in GitHub Desktop.
Save iamnasirudeen/65a2faffe5f08fac76d8d18eec4dfbe9 to your computer and use it in GitHub Desktop.
@extends('admin.layouts.app')
@section('content')
<div class="container-fluid" id="menu-app" data-id="{{$row->id ?? ''}}" v-cloak>
<div class="d-flex justify-content-between mb20">
<h1 class="title-bar">
@if(!empty($row->id))
{{__("Edit Menu:")}} @{{name}}
@else
{{__('Create new menu')}}
@endif
</h1>
</div>
<div class="alert" v-show="message.content" :class="message.type ? 'alert-success' : 'alert-danger'">
@{{message.content}}
</div>
<input type="text" class="form-control" value="{{$row->name ?? ''}}" v-model="name"
placeholder="{{__('Menu name')}}">
<br>
<br>
<div class="row">
<div class="col-md-4 col-xl-3 menu-item-types">
<div v-for="(type,index) in item_types" class="panel panel-toggle-able">
<div class="panel-title" @click="type.open = type.open ? false : true">@{{type.name}}
<i class="icon ion-md-arrow-dropdown"></i>
</div>
<div class="panel-body" v-show="type.open">
<input type="text" placeholder="{{__('Search...')}}" class="form-control input-sm menu-search"
@keyup="searchItems(type)" v-model="type.q">
<div class="list-scrollable" v-show="type.items.length">
<div v-for="item in type.items"><label><input v-model="type.selected" type="checkbox"
:value="item.id"> @{{item.name}}</label></div>
</div>
<div class="alert-text danger mt10" v-show="!type.items.length">{{__("No items found")}}</div>
<div class="text-right">
<span class="btn btn-sm btn-primary" @click="addToMenu(type)">{{__('Add to Menu')}}</span>
</div>
</div>
</div>
<div class="panel panel-toggle-able">
<div class="panel-title" @click="custom_show = custom_show ? false : true">{{__('Custom Url')}}
<i class="icon ion-md-arrow-dropdown"></i>
</div>
<div class="panel-body" v-show="custom_show">
<div class="form-group">
<label>{{__('URL')}}</label>
<input type="text" v-model="custom_url" class="form-control input-sm">
</div>
<div class="form-group">
<label>{{__('Link Text')}}</label>
<input type="text" v-model="custom_name" class="form-control input-sm">
</div>
<div class="text-right">
<span class="btn btn-sm btn-primary" @click="addCustomUrl">{{__('Add to Menu')}}</span>
</div>
</div>
</div>
</div>
<div class="col-md-8 col-xl-9">
<div class="panel">
<div class="panel-title">{{__('Menu items')}}</div>
<div class="panel-body">
<div class="menu-items-zone">
<Draggable-Tree :data="items" draggable cross-tree>
<div slot-scope="{data,store}" class="nestable-item-content" v-if="!data.isDragPlaceHolder">
<div class="menu-title">@{{data.name}}
<span class="menu-right">
<span class="model-name">@{{data.model_name}}</span>
<i class="icon ion-md-arrow-dropdown" @click="toogleItem(data)"></i>
</span>
</div>
<div class="menu-info" v-show="data._open">
<div class="form-group">
<label>{{__('Label')}}</label>
<input type="text" v-model="data.name" class="form-control input-sm">
</div>
<div class="form-group" v-show="data.item_model=='custom'">
<label>{{__('URL')}}</label>
<input type="text" v-model="data.url" class="form-control input-sm">
</div>
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label>{{__('Class')}}</label>
<input type="text" v-model="data.class"
class="form-control input-sm">
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label>{{__('Target')}}</label>
<select v-model="data.target" class="input-sm form-control">
<option value="">{{__('Normal')}}</option>
<option value="_blank">{{__('Open new tab')}}</option>
</select>
</div>
</div>
</div>
<div class="d-flex justify-content-between">
<a href='#' @click="deleteMenuItem($event,data,store)"
class="alert-text danger delete-menu-item">{{__('Delete')}}</a>
<span v-show="data.origin_name">{{__('Origin: ')}} <a
:href="data.origin_edit_url" target="_blank">@{{data.origin_name}}</a></span>
</div>
</div>
</div>
</Draggable-Tree>
</div>
<br>
<br>
<h3 class="panel-body-title">{{__('Menu Configs')}}</h3>
<div class="menu-locations">
@foreach($locations as $location=>$name)
<div>
<label><input type="checkbox" v-model="locations" value="{{$location}}">{{$name}}
</label>
</div>
@endforeach
</div>
</div>
<div class="panel-footer text-right">
<span class="alert-text" v-show="message.content" :class="message.type ? 'success' : 'danger'">@{{message.content}} &nbsp;</span>
<span class="btn btn-success" @click="saveMenu">{{__("Save Menu")}}</span>
</div>
</div>
</div>
</div>
</div>
<script>
var current_menu_items = {!! json_encode($row->items_json) ?? '[]' !!};
var current_menu_name = '{{$row->name}}';
var current_menu_locations = {!! json_encode($current_menu_locations) ?? '[]' !!};
var current_items_index = {{$row->lastIndex}};
</script>
@endsection
// import {VueNestableHandle, VueNestable} from 'vue-nestable'
import {DraggableTree} from 'vue-draggable-nested-tree'
// import draggable from 'vuedraggable'
// import NestedDraggable from './components/nested-draggable.vue'
(function ($) {
var id = $('#menu-app');
if (!id.length) {
return;
}
var menu_id = id.data('id');
new Vue({
el: '#menu-app',
components: {
// VueNestable,
// VueNestableHandle,
DraggableTree,
// draggable,
// NestedDraggable
},
data: {
items: current_menu_items,
item_types: [],
custom_url: '',
custom_name: "",
name: current_menu_name,
message: {
type: false,
content: ''
},
custom_show: false,
locations: current_menu_locations,
currentIndex: current_items_index + 1
},
mounted() {
this.reloadTypes();
// if(menu_id){
// this.reloadItems();
// }
},
methods: {
toogleItem(item) {
if (item._open) {
item._open = false;
} else {
item._open = true;
}
},
searchItems(type) {
// if(!type.q) return;
$.ajax({
url: bookingCore.url + '/admin/module/core/menu/searchTypeItems',
data: {
class: type.class,
q: type.q
},
dataType: 'json',
type: 'post',
success: function (res) {
if (res.status) {
type.items = res.data;
}
},
error: function (e) {
console.log(e);
}
})
},
reloadItems() {
var me = this;
$.ajax({
url: bookingCore.url + '/admin/module/core/menu/getItems',
dataType: 'json',
type: 'post',
data: {
id: menu_id
},
success: function (res) {
if (res.data && res.status) {
me.items = res.data;
}
},
error: function (e) {
console.log(e);
}
})
},
reloadTypes() {
var me = this;
$.ajax({
url: bookingCore.url + '/admin/module/core/menu/getTypes',
dataType: 'json',
type: 'post',
data: {},
success: function (res) {
if (res.data && res.status) {
me.item_types = res.data;
}
},
error: function (e) {
console.log(e);
}
})
},
addToMenu(type) {
if (!type.selected.length) {
return false;
}
for (var i = 0; i < type.items.length; i++) {
if (type.selected.indexOf(type.items[i].id) > -1) {
var item = Object.assign({}, type.items[i]);
// item._id = this.currentIndex + 1;
item._open = true;
this.items.push(item);
this.currentIndex += 1;
console.log(this.currentIndex);
}
}
type.selected = [];
},
addCustomUrl() {
if (!this.custom_name) return;
this.items.push({
name: this.custom_name,
url: this.custom_url,
item_model: 'custom',
_open: false,
// _id: this.items.length + 1
});
this.custom_name = '';
this.custom_url = '';
},
parseMenuItems:function(origins){
var items = [];
for(var i = 0; i < origins.length; i++){
var item = origins[i];
var tmp = Object.assign({},item);
delete tmp._vm;
delete tmp.parent;
delete tmp.style;
delete tmp.children;
delete tmp.style;
delete tmp.innerStyle;
delete tmp.innerBackClass;
delete tmp.innerBackStyle;
if(item.children){
tmp.children = this.parseMenuItems(item.children);
}
items.push(tmp);
}
return items;
},
saveMenu() {
var me = this;
var items = this.parseMenuItems(this.items);
$.ajax({
url: bookingCore.url + '/admin/module/core/menu/store',
dataType: 'json',
type: 'post',
data: {
id: menu_id,
items: JSON.stringify(items),
name: this.name,
locations: this.locations
},
success: function (res) {
if (res.message) {
me.message.content = res.message;
me.message.type = res.status;
}
if (res.url) {
window.location.href = res.url;
}
},
error: function (e) {
if (e.responseJSON.message) {
me.message.content = e.responseJSON.message;
me.message.type = false;
} else {
me.message.content = 'Can not save menu';
me.message.type = false;
}
}
})
},
deleteMenuItem(e, item,tree) {
e.preventDefault();
tree.deleteNode(item);
}
}
})
})(jQuery);
<?php
namespace Modules\Core\Admin;
use Illuminate\Http\Request;
use Modules\AdminController;
use Modules\Core\Models\Menu;
use Modules\News\Models\NewsCategory;
use Modules\Page\Models\Template;
class MenuController extends AdminController
{
public function __construct()
{
$this->setActiveMenu('admin/module/core/menu');
parent::__construct();
}
public function index()
{
$this->checkPermission('menu_view');
$data = [
'rows' => Menu::paginate(20),
'locations' => $this->getLocations(),
"menu_locations" => (array)json_decode(setting_item('menu_locations'), true)
];
return view('Core::admin.menu.index', $data);
}
public function getLocations()
{
return [
'primary' => __("Primary"),
'footer' => __("Footer"),
];
}
public function create()
{
$this->checkPermission('menu_create');
$data = [
'row' => new Menu(),
'locations' => $this->getLocations(),
'current_menu_locations' => [],
'breadcrumbs' => [
[
'name' => __('Menus'),
'url' => 'admin/module/core/menu'
],
[
'name' => __('Create new menu'),
'class' => 'active'
],
]
];
return view('Core::admin.menu.detail', $data);
}
public function edit($id)
{
$this->checkPermission('menu_update');
$row = Menu::find($id);
if (empty($row)) {
abort(404);
}
$setting = json_decode(setting_item('menu_locations'), true);
$current_menu_locations = [];
if (!empty($setting) and is_array($setting)) {
foreach ($setting as $location => $item) {
if ($item == $id) {
$current_menu_locations[] = $location;
}
}
}
$data = [
'row' => $row,
'locations' => $this->getLocations(),
'current_menu_locations' => $current_menu_locations,
'breadcrumbs' => [
[
'name' => __('Menus'),
'url' => 'admin/module/core/menu'
],
[
'name' => __('Edit: ') . $row->name,
'class' => 'active'
],
]
];
return view('Core::admin.menu.detail', $data);
}
public function searchTypeItems(Request $request)
{
$class = $request->input('class');
$q = $request->input('q');
if (class_exists($class) and method_exists($class, 'searchForMenu')) {
$this->sendSuccess([
'data' => call_user_func([
$class,
'searchForMenu'
], $q)
]);
}
$this->sendSuccess([
'data' => []
]);
}
public function getTypes()
{
$menuModels = [
[
'class' => \Modules\Page\Models\Page::class,
'name' => __("Page"),
'items' => \Modules\Page\Models\Page::searchForMenu()
],
[
'class' => \Modules\Tour\Models\Tour::class,
'name' => __("Tour"),
'items' => \Modules\Tour\Models\Tour::searchForMenu()
],
[
'class' => \Modules\Tour\Models\TourCategory::class,
'name' => __("Tour Category"),
'items' => \Modules\Tour\Models\TourCategory::searchForMenu()
],
[
'class' => \Modules\Location\Models\Location::class,
'name' => __("Location"),
'items' => \Modules\Location\Models\Location::searchForMenu()
],
[
'class' => \Modules\News\Models\News::class,
'name' => __("News"),
'items' => \Modules\News\Models\News::searchForMenu()
],
[
'class' => NewsCategory::class,
'name' => __("News Category"),
'items' => NewsCategory::searchForMenu()
],
];
foreach ($menuModels as $k => &$item) {
$item['q'] = '';
$item['open'] = !$k ? true : false;
$item['selected'] = [];
if (!empty($item['items'])) {
foreach ($item['items'] as &$menuItem) {
$menuItem['class'] = '';
$menuItem['target'] = '';
$menuItem['open'] = false;
$menuItem['item_model'] = $item['class'];
$menuItem['origin_name'] = $item['name'];
$menuItem['model_name'] = $item['class']::getModelName();
}
}
}
$this->sendSuccess(['data' => $menuModels]);
}
public function getItems(Request $request)
{
$menu = Menu::find($request->input('id'));
if (empty($menu))
$this->sendError(__("Menu not found"));
$this->sendSuccess(['data' => json_decode($menu->items, true)]);
}
public function store(Request $request)
{
$request->validate([
'items' => 'required',
'name' => 'required|max:255'
]);
if ($request->input('id')) {
$this->checkPermission('menu_update');
$menu = Menu::find($request->input('id'));
} else {
$this->checkPermission('menu_create');
$menu = new Menu();
}
if (empty($menu))
$this->sendError(__('Menu not found'));
$menu->items = $request->input('items');
$menu->name = $request->input('name');
$menu->save();
$setting = json_decode(setting_item('menu_locations'), true);
$hasChange = false;
if (!empty($setting)) {
foreach ($setting as $location => $menuId) {
if ($menuId == $menu->id) {
$setting[$location] = '';
}
}
}
// Save Locations
$locations = $request->input('locations');
if (!empty($locations)) {
foreach ($locations as $location) {
if (!isset($setting[$location]))
$setting[$location] = [];
$setting[$location] = $menu->id;
}
}
setting_update_item('menu_locations', json_encode($setting));
$this->sendSuccess([
'url' => $request->input('id') ? '' : url('admin/module/core/menu/edit/' . $menu->id)
], __('Your menu has been saved'));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment