Egorka
7 years ago
41 changed files with 2225 additions and 5 deletions
@ -0,0 +1,32 @@ |
|||||||
|
<?php |
||||||
|
/** |
||||||
|
* Created by Error202 |
||||||
|
* Date: 11.07.2018 |
||||||
|
*/ |
||||||
|
|
||||||
|
namespace backend\components\menu\assets; |
||||||
|
|
||||||
|
|
||||||
|
use yii\web\AssetBundle; |
||||||
|
|
||||||
|
class MenuAsset extends AssetBundle |
||||||
|
{ |
||||||
|
public $sourcePath = '@backend/components/menu'; |
||||||
|
public $css = [ |
||||||
|
'css/menu.css', |
||||||
|
]; |
||||||
|
|
||||||
|
public $js = [ |
||||||
|
'js/jquery.nestable.js', |
||||||
|
'js/menu.js' |
||||||
|
]; |
||||||
|
|
||||||
|
public $depends = [ |
||||||
|
'yii\web\YiiAsset', |
||||||
|
'yii\bootstrap\BootstrapPluginAsset', |
||||||
|
]; |
||||||
|
|
||||||
|
public $publishOptions = [ |
||||||
|
'forceCopy' => YII_ENV_DEV ? true : false, |
||||||
|
]; |
||||||
|
} |
File diff suppressed because one or more lines are too long
@ -0,0 +1,196 @@ |
|||||||
|
/*.cf:after { visibility: hidden; display: block; font-size: 0; content: " "; clear: both; height: 0; } |
||||||
|
* html .cf { zoom: 1; } |
||||||
|
*:first-child+html .cf { zoom: 1; } |
||||||
|
|
||||||
|
html { margin: 0; padding: 0; } |
||||||
|
body { font-size: 100%; margin: 0; padding: 1.75em; font-family: 'Helvetica Neue', Arial, sans-serif; } |
||||||
|
|
||||||
|
h1 { font-size: 1.75em; margin: 0 0 0.6em 0; } |
||||||
|
|
||||||
|
a { color: #2996cc; } |
||||||
|
a:hover { text-decoration: none; } |
||||||
|
|
||||||
|
p { line-height: 1.5em; } |
||||||
|
.small { color: #666; font-size: 0.875em; } |
||||||
|
.large { font-size: 1.25em; }*/ |
||||||
|
|
||||||
|
/** |
||||||
|
* Nestable |
||||||
|
*/ |
||||||
|
|
||||||
|
.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-collapsed .dd-list { |
||||||
|
display: none; |
||||||
|
} |
||||||
|
|
||||||
|
.dd-item, |
||||||
|
.dd-empty, |
||||||
|
.dd-placeholder { |
||||||
|
display: block; |
||||||
|
position: relative; |
||||||
|
margin: 0; padding: 1px; |
||||||
|
min-height: 20px; |
||||||
|
font-size: 13px; |
||||||
|
line-height: 10px; |
||||||
|
} |
||||||
|
|
||||||
|
.dd-handle { |
||||||
|
display: block; |
||||||
|
height: 100%; |
||||||
|
margin: 5px 0; |
||||||
|
padding: 5px 10px; |
||||||
|
color: #333; |
||||||
|
text-decoration: none; |
||||||
|
font-weight: bold; |
||||||
|
/*border: 1px solid #ccc;*/ |
||||||
|
background: #fafafa; |
||||||
|
background: -webkit-linear-gradient(top, #fafafa 0%, #eee 100%); |
||||||
|
background: -moz-linear-gradient(top, #fafafa 0%, #eee 100%); |
||||||
|
background: linear-gradient(top, #fafafa 0%, #eee 100%); |
||||||
|
-webkit-border-radius: 3px; |
||||||
|
border-radius: 3px; |
||||||
|
box-sizing: border-box; |
||||||
|
-moz-box-sizing: border-box; |
||||||
|
} |
||||||
|
.dd-handle:hover { color: #2ea8e5; background: #fff; } |
||||||
|
|
||||||
|
.dd-item > button { |
||||||
|
display: block; |
||||||
|
position: relative; |
||||||
|
cursor: pointer; |
||||||
|
float: left; |
||||||
|
width: 25px; height: 30px; |
||||||
|
margin: 9px 0; padding: 0; |
||||||
|
text-indent: 100%; |
||||||
|
white-space: nowrap; |
||||||
|
overflow: hidden; |
||||||
|
border: 0; |
||||||
|
background: transparent; |
||||||
|
font-size: 20px; |
||||||
|
line-height: 1; |
||||||
|
text-align: center; |
||||||
|
font-weight: bold; |
||||||
|
z-index: 5; |
||||||
|
color: #999; |
||||||
|
} |
||||||
|
.dd-item > button:before { |
||||||
|
content: '+'; |
||||||
|
display: block; |
||||||
|
position: absolute; |
||||||
|
width: 100%; |
||||||
|
text-align: center; |
||||||
|
text-indent: 0; |
||||||
|
} |
||||||
|
.dd-item > button[data-action="collapse"]:before { content: '-'; } |
||||||
|
|
||||||
|
.dd-placeholder, |
||||||
|
.dd-empty { |
||||||
|
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-image: -webkit-linear-gradient(45deg, #fff 25%, transparent 25%, transparent 75%, #fff 75%, #fff), |
||||||
|
-webkit-linear-gradient(45deg, #fff 25%, transparent 25%, transparent 75%, #fff 75%, #fff); |
||||||
|
background-image: -moz-linear-gradient(45deg, #fff 25%, transparent 25%, transparent 75%, #fff 75%, #fff), |
||||||
|
-moz-linear-gradient(45deg, #fff 25%, transparent 25%, transparent 75%, #fff 75%, #fff); |
||||||
|
background-image: linear-gradient(45deg, #fff 25%, transparent 25%, transparent 75%, #fff 75%, #fff), |
||||||
|
linear-gradient(45deg, #fff 25%, transparent 25%, transparent 75%, #fff 75%, #fff); |
||||||
|
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 { |
||||||
|
-webkit-box-shadow: 2px 4px 6px 0 rgba(0,0,0,.1); |
||||||
|
box-shadow: 2px 4px 6px 0 rgba(0,0,0,.1); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@media only screen and (min-width: 700px) { |
||||||
|
|
||||||
|
.dd { float: left; width: 48%; } |
||||||
|
.dd + .dd { margin-left: 2%; } |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
.dd-hover > .dd-handle { background: #2ea8e5 !important; } |
||||||
|
|
||||||
|
/** |
||||||
|
* Nestable Draggable Handles |
||||||
|
*/ |
||||||
|
|
||||||
|
.dd3-content { |
||||||
|
display: block; |
||||||
|
margin: 5px 0; |
||||||
|
padding: 0; |
||||||
|
color: #333; |
||||||
|
text-decoration: none; |
||||||
|
font-weight: bold; |
||||||
|
background: #fafafa; |
||||||
|
background: -webkit-linear-gradient(top, #fafafa 0%, #eee 100%); |
||||||
|
background: -moz-linear-gradient(top, #fafafa 0%, #eee 100%); |
||||||
|
background: linear-gradient(top, #fafafa 0%, #eee 100%); |
||||||
|
-webkit-border-radius: 3px; |
||||||
|
border-radius: 3px; |
||||||
|
box-sizing: border-box; -moz-box-sizing: border-box; |
||||||
|
} |
||||||
|
.dd3-content:hover { |
||||||
|
color: #2ea8e5; |
||||||
|
background: #fff; |
||||||
|
} |
||||||
|
|
||||||
|
.dd-dragel > .dd3-item > .dd3-content { margin: 0; } |
||||||
|
|
||||||
|
.dd3-item > button { margin-left: 30px; } |
||||||
|
|
||||||
|
.dd3-handle { position: absolute; margin: 0; left: 0; top: 0; cursor: pointer; width: 30px; text-indent: 100%; white-space: nowrap; overflow: hidden; |
||||||
|
border: 1px solid #aaa; |
||||||
|
background: #ddd; |
||||||
|
background: -webkit-linear-gradient(top, #ddd 0%, #bbb 100%); |
||||||
|
background: -moz-linear-gradient(top, #ddd 0%, #bbb 100%); |
||||||
|
background: linear-gradient(top, #ddd 0%, #bbb 100%); |
||||||
|
border-top-right-radius: 0; |
||||||
|
border-bottom-right-radius: 0; |
||||||
|
} |
||||||
|
.dd3-handle:before { |
||||||
|
content: "\f047"; |
||||||
|
font-family: FontAwesome; |
||||||
|
display: block; |
||||||
|
position: absolute; |
||||||
|
left: 0; top: 10px; |
||||||
|
width: 100%; |
||||||
|
text-align: center; |
||||||
|
text-indent: 0; |
||||||
|
color: #fff; |
||||||
|
font-size: 15px; |
||||||
|
font-weight: normal; |
||||||
|
} |
||||||
|
.dd3-handle:hover { background: #ddd; } |
||||||
|
|
||||||
|
.panel-group { |
||||||
|
margin-bottom: 0 !important; |
||||||
|
} |
||||||
|
.panel-heading { |
||||||
|
position: relative; |
||||||
|
} |
||||||
|
.panel-heading h4 { |
||||||
|
padding-left: 25px; |
||||||
|
} |
File diff suppressed because one or more lines are too long
@ -0,0 +1,484 @@ |
|||||||
|
/*! |
||||||
|
* Nestable jQuery Plugin - Copyright (c) 2012 David Bushell - http://dbushell.com/
|
||||||
|
* Dual-licensed under the BSD or MIT licenses |
||||||
|
*/ |
||||||
|
;(function($, window, document, undefined) |
||||||
|
{ |
||||||
|
var hasTouch = 'ontouchstart' in document; |
||||||
|
|
||||||
|
/** |
||||||
|
* Detect CSS pointer-events property |
||||||
|
* events are normally disabled on the dragging element to avoid conflicts |
||||||
|
* https://github.com/ausi/Feature-detection-technique-for-pointer-events/blob/master/modernizr-pointerevents.js
|
||||||
|
*/ |
||||||
|
var hasPointerEvents = (function() |
||||||
|
{ |
||||||
|
var el = document.createElement('div'), |
||||||
|
docEl = document.documentElement; |
||||||
|
if (!('pointerEvents' in el.style)) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
el.style.pointerEvents = 'auto'; |
||||||
|
el.style.pointerEvents = 'x'; |
||||||
|
docEl.appendChild(el); |
||||||
|
var supports = window.getComputedStyle && window.getComputedStyle(el, '').pointerEvents === 'auto'; |
||||||
|
docEl.removeChild(el); |
||||||
|
return !!supports; |
||||||
|
})(); |
||||||
|
|
||||||
|
var defaults = { |
||||||
|
listNodeName : 'ol', |
||||||
|
itemNodeName : 'li', |
||||||
|
rootClass : 'dd', |
||||||
|
listClass : 'dd-list', |
||||||
|
itemClass : 'dd-item', |
||||||
|
dragClass : 'dd-dragel', |
||||||
|
handleClass : 'dd-handle', |
||||||
|
collapsedClass : 'dd-collapsed', |
||||||
|
placeClass : 'dd-placeholder', |
||||||
|
noDragClass : 'dd-nodrag', |
||||||
|
emptyClass : 'dd-empty', |
||||||
|
expandBtnHTML : '<button data-action="expand" type="button">Expand</button>', |
||||||
|
collapseBtnHTML : '<button data-action="collapse" type="button">Collapse</button>', |
||||||
|
group : 0, |
||||||
|
maxDepth : 5, |
||||||
|
threshold : 20 |
||||||
|
}; |
||||||
|
|
||||||
|
function Plugin(element, options) |
||||||
|
{ |
||||||
|
this.w = $(document); |
||||||
|
this.el = $(element); |
||||||
|
this.options = $.extend({}, defaults, options); |
||||||
|
this.init(); |
||||||
|
} |
||||||
|
|
||||||
|
Plugin.prototype = { |
||||||
|
|
||||||
|
init: function() |
||||||
|
{ |
||||||
|
var list = this; |
||||||
|
|
||||||
|
list.reset(); |
||||||
|
|
||||||
|
list.el.data('nestable-group', this.options.group); |
||||||
|
|
||||||
|
list.placeEl = $('<div class="' + list.options.placeClass + '"/>'); |
||||||
|
|
||||||
|
$.each(this.el.find(list.options.itemNodeName), function(k, el) { |
||||||
|
list.setParent($(el)); |
||||||
|
}); |
||||||
|
|
||||||
|
list.el.on('click', 'button', function(e) { |
||||||
|
if (list.dragEl) { |
||||||
|
return; |
||||||
|
} |
||||||
|
var target = $(e.currentTarget), |
||||||
|
action = target.data('action'), |
||||||
|
item = target.parent(list.options.itemNodeName); |
||||||
|
if (action === 'collapse') { |
||||||
|
list.collapseItem(item); |
||||||
|
} |
||||||
|
if (action === 'expand') { |
||||||
|
list.expandItem(item); |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
var onStartEvent = function(e) |
||||||
|
{ |
||||||
|
var handle = $(e.target); |
||||||
|
if (!handle.hasClass(list.options.handleClass)) { |
||||||
|
if (handle.closest('.' + list.options.noDragClass).length) { |
||||||
|
return; |
||||||
|
} |
||||||
|
handle = handle.closest('.' + list.options.handleClass); |
||||||
|
} |
||||||
|
|
||||||
|
if (!handle.length || list.dragEl) { |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
list.isTouch = /^touch/.test(e.type); |
||||||
|
if (list.isTouch && e.touches.length !== 1) { |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
e.preventDefault(); |
||||||
|
list.dragStart(e.touches ? e.touches[0] : e); |
||||||
|
}; |
||||||
|
|
||||||
|
var onMoveEvent = function(e) |
||||||
|
{ |
||||||
|
if (list.dragEl) { |
||||||
|
e.preventDefault(); |
||||||
|
list.dragMove(e.touches ? e.touches[0] : e); |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
var onEndEvent = function(e) |
||||||
|
{ |
||||||
|
if (list.dragEl) { |
||||||
|
e.preventDefault(); |
||||||
|
list.dragStop(e.touches ? e.touches[0] : e); |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
if (hasTouch) { |
||||||
|
list.el[0].addEventListener('touchstart', onStartEvent, false); |
||||||
|
window.addEventListener('touchmove', onMoveEvent, false); |
||||||
|
window.addEventListener('touchend', onEndEvent, false); |
||||||
|
window.addEventListener('touchcancel', onEndEvent, false); |
||||||
|
} |
||||||
|
|
||||||
|
list.el.on('mousedown', onStartEvent); |
||||||
|
list.w.on('mousemove', onMoveEvent); |
||||||
|
list.w.on('mouseup', onEndEvent); |
||||||
|
|
||||||
|
}, |
||||||
|
|
||||||
|
serialize: function() |
||||||
|
{ |
||||||
|
var data, |
||||||
|
depth = 0, |
||||||
|
list = this; |
||||||
|
step = function(level, depth) |
||||||
|
{ |
||||||
|
var array = [ ], |
||||||
|
items = level.children(list.options.itemNodeName); |
||||||
|
items.each(function() |
||||||
|
{ |
||||||
|
var li = $(this), |
||||||
|
item = $.extend({}, li.data()), |
||||||
|
sub = li.children(list.options.listNodeName); |
||||||
|
if (sub.length) { |
||||||
|
item.children = step(sub, depth + 1); |
||||||
|
} |
||||||
|
array.push(item); |
||||||
|
}); |
||||||
|
return array; |
||||||
|
}; |
||||||
|
data = step(list.el.find(list.options.listNodeName).first(), depth); |
||||||
|
return data; |
||||||
|
}, |
||||||
|
|
||||||
|
serialise: function() |
||||||
|
{ |
||||||
|
return this.serialize(); |
||||||
|
}, |
||||||
|
|
||||||
|
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 = false; |
||||||
|
this.moving = false; |
||||||
|
this.dragEl = null; |
||||||
|
this.dragRootEl = null; |
||||||
|
this.dragDepth = 0; |
||||||
|
this.hasNewRoot = false; |
||||||
|
this.pointEl = null; |
||||||
|
}, |
||||||
|
|
||||||
|
expandItem: function(li) |
||||||
|
{ |
||||||
|
li.removeClass(this.options.collapsedClass); |
||||||
|
li.children('[data-action="expand"]').hide(); |
||||||
|
li.children('[data-action="collapse"]').show(); |
||||||
|
li.children(this.options.listNodeName).show(); |
||||||
|
}, |
||||||
|
|
||||||
|
collapseItem: function(li) |
||||||
|
{ |
||||||
|
var lists = li.children(this.options.listNodeName); |
||||||
|
if (lists.length) { |
||||||
|
li.addClass(this.options.collapsedClass); |
||||||
|
li.children('[data-action="collapse"]').hide(); |
||||||
|
li.children('[data-action="expand"]').show(); |
||||||
|
li.children(this.options.listNodeName).hide(); |
||||||
|
} |
||||||
|
}, |
||||||
|
|
||||||
|
expandAll: function() |
||||||
|
{ |
||||||
|
var list = this; |
||||||
|
list.el.find(list.options.itemNodeName).each(function() { |
||||||
|
list.expandItem($(this)); |
||||||
|
}); |
||||||
|
}, |
||||||
|
|
||||||
|
collapseAll: function() |
||||||
|
{ |
||||||
|
var list = this; |
||||||
|
list.el.find(list.options.itemNodeName).each(function() { |
||||||
|
list.collapseItem($(this)); |
||||||
|
}); |
||||||
|
}, |
||||||
|
|
||||||
|
setParent: function(li) |
||||||
|
{ |
||||||
|
if (li.children(this.options.listNodeName).length) { |
||||||
|
li.prepend($(this.options.expandBtnHTML)); |
||||||
|
li.prepend($(this.options.collapseBtnHTML)); |
||||||
|
} |
||||||
|
li.children('[data-action="expand"]').hide(); |
||||||
|
}, |
||||||
|
|
||||||
|
unsetParent: function(li) |
||||||
|
{ |
||||||
|
li.removeClass(this.options.collapsedClass); |
||||||
|
li.children('[data-action]').remove(); |
||||||
|
li.children(this.options.listNodeName).remove(); |
||||||
|
}, |
||||||
|
|
||||||
|
dragStart: function(e) |
||||||
|
{ |
||||||
|
var mouse = this.mouse, |
||||||
|
target = $(e.target), |
||||||
|
dragItem = target.closest(this.options.itemNodeName); |
||||||
|
|
||||||
|
this.placeEl.css('height', dragItem.height()); |
||||||
|
|
||||||
|
mouse.offsetX = e.offsetX !== undefined ? e.offsetX : e.pageX - target.offset().left; |
||||||
|
mouse.offsetY = e.offsetY !== undefined ? e.offsetY : e.pageY - target.offset().top; |
||||||
|
mouse.startX = mouse.lastX = e.pageX; |
||||||
|
mouse.startY = mouse.lastY = e.pageY; |
||||||
|
|
||||||
|
this.dragRootEl = this.el; |
||||||
|
|
||||||
|
this.dragEl = $(document.createElement(this.options.listNodeName)).addClass(this.options.listClass + ' ' + this.options.dragClass); |
||||||
|
this.dragEl.css('width', dragItem.width()); |
||||||
|
|
||||||
|
dragItem.after(this.placeEl); |
||||||
|
dragItem[0].parentNode.removeChild(dragItem[0]); |
||||||
|
dragItem.appendTo(this.dragEl); |
||||||
|
|
||||||
|
$(document.body).append(this.dragEl); |
||||||
|
this.dragEl.css({ |
||||||
|
'left' : e.pageX - mouse.offsetX, |
||||||
|
'top' : e.pageY - mouse.offsetY |
||||||
|
}); |
||||||
|
// total depth of dragging item
|
||||||
|
var i, depth, |
||||||
|
items = this.dragEl.find(this.options.itemNodeName); |
||||||
|
for (i = 0; i < items.length; i++) { |
||||||
|
depth = $(items[i]).parents(this.options.listNodeName).length; |
||||||
|
if (depth > this.dragDepth) { |
||||||
|
this.dragDepth = depth; |
||||||
|
} |
||||||
|
} |
||||||
|
}, |
||||||
|
|
||||||
|
dragStop: function(e) |
||||||
|
{ |
||||||
|
var el = this.dragEl.children(this.options.itemNodeName).first(); |
||||||
|
el[0].parentNode.removeChild(el[0]); |
||||||
|
this.placeEl.replaceWith(el); |
||||||
|
|
||||||
|
this.dragEl.remove(); |
||||||
|
this.el.trigger('change'); |
||||||
|
if (this.hasNewRoot) { |
||||||
|
this.dragRootEl.trigger('change'); |
||||||
|
} |
||||||
|
this.reset(); |
||||||
|
}, |
||||||
|
|
||||||
|
dragMove: function(e) |
||||||
|
{ |
||||||
|
var list, parent, prev, next, depth, |
||||||
|
opt = this.options, |
||||||
|
mouse = this.mouse; |
||||||
|
|
||||||
|
this.dragEl.css({ |
||||||
|
'left' : e.pageX - mouse.offsetX, |
||||||
|
'top' : e.pageY - mouse.offsetY |
||||||
|
}); |
||||||
|
|
||||||
|
// mouse position last events
|
||||||
|
mouse.lastX = mouse.nowX; |
||||||
|
mouse.lastY = mouse.nowY; |
||||||
|
// mouse position this events
|
||||||
|
mouse.nowX = e.pageX; |
||||||
|
mouse.nowY = e.pageY; |
||||||
|
// distance mouse moved between events
|
||||||
|
mouse.distX = mouse.nowX - mouse.lastX; |
||||||
|
mouse.distY = mouse.nowY - mouse.lastY; |
||||||
|
// direction mouse was moving
|
||||||
|
mouse.lastDirX = mouse.dirX; |
||||||
|
mouse.lastDirY = mouse.dirY; |
||||||
|
// direction mouse is now moving (on both axis)
|
||||||
|
mouse.dirX = mouse.distX === 0 ? 0 : mouse.distX > 0 ? 1 : -1; |
||||||
|
mouse.dirY = mouse.distY === 0 ? 0 : mouse.distY > 0 ? 1 : -1; |
||||||
|
// axis mouse is now moving on
|
||||||
|
var newAx = Math.abs(mouse.distX) > Math.abs(mouse.distY) ? 1 : 0; |
||||||
|
|
||||||
|
// do nothing on first move
|
||||||
|
if (!mouse.moving) { |
||||||
|
mouse.dirAx = newAx; |
||||||
|
mouse.moving = true; |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
// calc distance moved on this axis (and direction)
|
||||||
|
if (mouse.dirAx !== newAx) { |
||||||
|
mouse.distAxX = 0; |
||||||
|
mouse.distAxY = 0; |
||||||
|
} else { |
||||||
|
mouse.distAxX += Math.abs(mouse.distX); |
||||||
|
if (mouse.dirX !== 0 && mouse.dirX !== mouse.lastDirX) { |
||||||
|
mouse.distAxX = 0; |
||||||
|
} |
||||||
|
mouse.distAxY += Math.abs(mouse.distY); |
||||||
|
if (mouse.dirY !== 0 && mouse.dirY !== mouse.lastDirY) { |
||||||
|
mouse.distAxY = 0; |
||||||
|
} |
||||||
|
} |
||||||
|
mouse.dirAx = newAx; |
||||||
|
|
||||||
|
/** |
||||||
|
* move horizontal |
||||||
|
*/ |
||||||
|
if (mouse.dirAx && mouse.distAxX >= opt.threshold) { |
||||||
|
// reset move distance on x-axis for new phase
|
||||||
|
mouse.distAxX = 0; |
||||||
|
prev = this.placeEl.prev(opt.itemNodeName); |
||||||
|
// increase horizontal level if previous sibling exists and is not collapsed
|
||||||
|
if (mouse.distX > 0 && prev.length && !prev.hasClass(opt.collapsedClass)) { |
||||||
|
// cannot increase level when item above is collapsed
|
||||||
|
list = prev.find(opt.listNodeName).last(); |
||||||
|
// check if depth limit has reached
|
||||||
|
depth = this.placeEl.parents(opt.listNodeName).length; |
||||||
|
if (depth + this.dragDepth <= opt.maxDepth) { |
||||||
|
// create new sub-level if one doesn't exist
|
||||||
|
if (!list.length) { |
||||||
|
list = $('<' + opt.listNodeName + '/>').addClass(opt.listClass); |
||||||
|
list.append(this.placeEl); |
||||||
|
prev.append(list); |
||||||
|
this.setParent(prev); |
||||||
|
} else { |
||||||
|
// else append to next level up
|
||||||
|
list = prev.children(opt.listNodeName).last(); |
||||||
|
list.append(this.placeEl); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
// decrease horizontal level
|
||||||
|
if (mouse.distX < 0) { |
||||||
|
// we can't decrease a level if an item preceeds the current one
|
||||||
|
next = this.placeEl.next(opt.itemNodeName); |
||||||
|
if (!next.length) { |
||||||
|
parent = this.placeEl.parent(); |
||||||
|
this.placeEl.closest(opt.itemNodeName).after(this.placeEl); |
||||||
|
if (!parent.children().length) { |
||||||
|
this.unsetParent(parent.parent()); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
var isEmpty = false; |
||||||
|
|
||||||
|
// find list item under cursor
|
||||||
|
if (!hasPointerEvents) { |
||||||
|
this.dragEl[0].style.visibility = 'hidden'; |
||||||
|
} |
||||||
|
this.pointEl = $(document.elementFromPoint(e.pageX - document.body.scrollLeft, e.pageY - (window.pageYOffset || document.documentElement.scrollTop))); |
||||||
|
if (!hasPointerEvents) { |
||||||
|
this.dragEl[0].style.visibility = 'visible'; |
||||||
|
} |
||||||
|
if (this.pointEl.hasClass(opt.handleClass)) { |
||||||
|
this.pointEl = this.pointEl.parent(opt.itemNodeName); |
||||||
|
} |
||||||
|
if (this.pointEl.hasClass(opt.emptyClass)) { |
||||||
|
isEmpty = true; |
||||||
|
} |
||||||
|
else if (!this.pointEl.length || !this.pointEl.hasClass(opt.itemClass)) { |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
// find parent list of item under cursor
|
||||||
|
var pointElRoot = this.pointEl.closest('.' + opt.rootClass), |
||||||
|
isNewRoot = this.dragRootEl.data('nestable-id') !== pointElRoot.data('nestable-id'); |
||||||
|
|
||||||
|
/** |
||||||
|
* move vertical |
||||||
|
*/ |
||||||
|
if (!mouse.dirAx || isNewRoot || isEmpty) { |
||||||
|
// check if groups match if dragging over new root
|
||||||
|
if (isNewRoot && opt.group !== pointElRoot.data('nestable-group')) { |
||||||
|
return; |
||||||
|
} |
||||||
|
// check depth limit
|
||||||
|
depth = this.dragDepth - 1 + this.pointEl.parents(opt.listNodeName).length; |
||||||
|
if (depth > opt.maxDepth) { |
||||||
|
return; |
||||||
|
} |
||||||
|
var before = e.pageY < (this.pointEl.offset().top + this.pointEl.height() / 2); |
||||||
|
parent = this.placeEl.parent(); |
||||||
|
// if empty create new list to replace empty placeholder
|
||||||
|
if (isEmpty) { |
||||||
|
list = $(document.createElement(opt.listNodeName)).addClass(opt.listClass); |
||||||
|
list.append(this.placeEl); |
||||||
|
this.pointEl.replaceWith(list); |
||||||
|
} |
||||||
|
else if (before) { |
||||||
|
this.pointEl.before(this.placeEl); |
||||||
|
} |
||||||
|
else { |
||||||
|
this.pointEl.after(this.placeEl); |
||||||
|
} |
||||||
|
if (!parent.children().length) { |
||||||
|
this.unsetParent(parent.parent()); |
||||||
|
} |
||||||
|
if (!this.dragRootEl.find(opt.itemNodeName).length) { |
||||||
|
this.dragRootEl.append('<div class="' + opt.emptyClass + '"/>'); |
||||||
|
} |
||||||
|
// parent root list has changed
|
||||||
|
if (isNewRoot) { |
||||||
|
this.dragRootEl = pointElRoot; |
||||||
|
this.hasNewRoot = this.el[0] !== this.dragRootEl[0]; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
}; |
||||||
|
|
||||||
|
$.fn.nestable = function(params) |
||||||
|
{ |
||||||
|
var lists = this, |
||||||
|
retval = this; |
||||||
|
|
||||||
|
lists.each(function() |
||||||
|
{ |
||||||
|
var plugin = $(this).data("nestable"); |
||||||
|
|
||||||
|
if (!plugin) { |
||||||
|
$(this).data("nestable", new Plugin(this, params)); |
||||||
|
$(this).data("nestable-id", new Date().getTime()); |
||||||
|
} else { |
||||||
|
if (typeof params === 'string' && typeof plugin[params] === 'function') { |
||||||
|
retval = plugin[params](); |
||||||
|
} |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
return retval || lists; |
||||||
|
}; |
||||||
|
|
||||||
|
})(window.jQuery || window.Zepto, window, document); |
@ -0,0 +1,60 @@ |
|||||||
|
$(document).ready(function() |
||||||
|
{ |
||||||
|
$('#nestable3').nestable(); |
||||||
|
|
||||||
|
$('#serialize').click(function(){ |
||||||
|
serializeTree(); |
||||||
|
}); |
||||||
|
|
||||||
|
//$('#nestable3').on('change', function() {
|
||||||
|
/* on change event */ |
||||||
|
//alert('Order changed');
|
||||||
|
//});
|
||||||
|
|
||||||
|
//$('.panel-group').mouseover(function(ev) {
|
||||||
|
// $(this).find('.dd-item').trigger(ev);
|
||||||
|
//});
|
||||||
|
//$('.panel-group, .panel, .panel-heading, .panel-title, .panel-collapse, .panel-body').trigger('mouseover');
|
||||||
|
//$('.panel-group, .panel, .panel-heading, .panel-title, .panel-collapse, .panel-body, .dd-handle').mouseover();
|
||||||
|
//$('.panel-group, .panel, .panel-heading, .panel-title, .panel-collapse, .panel-body, .dd-handle').mouseenter();
|
||||||
|
}); |
||||||
|
|
||||||
|
function serializeTree() { |
||||||
|
//if (window.JSON) {
|
||||||
|
//var serialized = JSON.stringify($('#nestable3').nestable('serialize'));
|
||||||
|
//$('#output').text(serialized+'\n\n');
|
||||||
|
var arr = getPositions($('#nestable3').nestable('serialize')); |
||||||
|
return JSON.stringify(arr); |
||||||
|
//$('#output').text(JSON.stringify(arr));
|
||||||
|
//} else {
|
||||||
|
//$('#output').text('JSON browser support required for this demo.');
|
||||||
|
//}
|
||||||
|
} |
||||||
|
|
||||||
|
function getPositions(array, parent_id) { |
||||||
|
parent_id = parent_id || 0; |
||||||
|
var new_array = []; |
||||||
|
for (var i = 0; i < array.length; i++) { |
||||||
|
new_array.push([array[i].id, parent_id]); |
||||||
|
if (array[i].hasOwnProperty('children')) { |
||||||
|
new_array = new_array.concat(getPositions( array[i].children, array[i].id )); |
||||||
|
} |
||||||
|
} |
||||||
|
return new_array; |
||||||
|
} |
||||||
|
|
||||||
|
function sendTree(menu_id, url, redirect) { |
||||||
|
var json = serializeTree(); |
||||||
|
|
||||||
|
$.ajax({ |
||||||
|
url: url, |
||||||
|
type: 'POST', |
||||||
|
data: { json : json }, |
||||||
|
success: function(){ |
||||||
|
document.location.href = redirect; |
||||||
|
}, |
||||||
|
error: function(){ |
||||||
|
alert('Error: ' + res.message); |
||||||
|
} |
||||||
|
}); |
||||||
|
} |
@ -0,0 +1,48 @@ |
|||||||
|
<?php |
||||||
|
/** |
||||||
|
* Created by Error202 |
||||||
|
* Date: 11.07.2018 |
||||||
|
*/ |
||||||
|
|
||||||
|
namespace backend\components\menu\widgets; |
||||||
|
|
||||||
|
|
||||||
|
use core\entities\menu\Menu; |
||||||
|
use core\entities\menu\MenuItem; |
||||||
|
use yii\base\Widget; |
||||||
|
|
||||||
|
class MenuEditorWidget extends Widget |
||||||
|
{ |
||||||
|
public $menu_id; |
||||||
|
|
||||||
|
public function run() |
||||||
|
{ |
||||||
|
$menu = Menu::findOne($this->menu_id); |
||||||
|
$items = $menu->items; |
||||||
|
|
||||||
|
return $this->render('menu', [ |
||||||
|
'items' => $this->getMenu($items), |
||||||
|
'menu' => $menu, |
||||||
|
]); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @param $items MenuItem[] |
||||||
|
* |
||||||
|
* @return array |
||||||
|
*/ |
||||||
|
private function getMenu($items, $paren_id = null) |
||||||
|
{ |
||||||
|
$array = []; |
||||||
|
foreach ($items as $item) { |
||||||
|
if ($item->parent_id != $paren_id) { |
||||||
|
continue; |
||||||
|
} |
||||||
|
$array[$item->id]['item'] = $item; |
||||||
|
if ($children = $item->children) { |
||||||
|
$array[$item->id]['children'] = $this->getMenu($children, $item->id); |
||||||
|
} |
||||||
|
} |
||||||
|
return $array; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,41 @@ |
|||||||
|
<?php |
||||||
|
/** |
||||||
|
* Created by Error202 |
||||||
|
* Date: 11.07.2018 |
||||||
|
*/ |
||||||
|
|
||||||
|
/** |
||||||
|
* @var $this \yii\web\View |
||||||
|
* @var $item array |
||||||
|
*/ |
||||||
|
|
||||||
|
/* @var $menu_item \core\entities\menu\MenuItem */ |
||||||
|
$menu_item = $item['item']; |
||||||
|
|
||||||
|
?> |
||||||
|
|
||||||
|
<li class="dd-item dd3-item" data-id="<?= $menu_item->id ?>">
|
||||||
|
<div class="dd3-content"> |
||||||
|
<div class="panel-group" id="accordion"> |
||||||
|
<div class="panel panel-default"> |
||||||
|
<div class="panel-heading"> |
||||||
|
<h4 class="panel-title"> |
||||||
|
<div class="dd-handle dd3-handle"> </div> |
||||||
|
<a data-toggle="collapse" data-parent="#accordion" href="#collapse<?= $menu_item->id ?>"><?= $menu_item->name ?> |
||||||
|
<i class="fa fa-angle-down pull-right" aria-hidden="true"></i></a> |
||||||
|
</h4> |
||||||
|
</div> |
||||||
|
<div id="collapse<?= $menu_item->id ?>" class="panel-collapse collapse">
|
||||||
|
<div class="panel-body"> |
||||||
|
Content Panel |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
|
||||||
|
<?php if (isset($item['children'])): ?> |
||||||
|
<?= menu_generate($item['children']) ?> |
||||||
|
<?php endif; ?> |
||||||
|
|
||||||
|
</li> |
@ -0,0 +1,155 @@ |
|||||||
|
<?php |
||||||
|
/** |
||||||
|
* Created by Error202 |
||||||
|
* Date: 11.07.2018 |
||||||
|
*/ |
||||||
|
|
||||||
|
/** |
||||||
|
* @var $this \yii\web\View |
||||||
|
* @var $items array |
||||||
|
* @var $menu \core\entities\menu\Menu |
||||||
|
*/ |
||||||
|
|
||||||
|
use backend\components\menu\assets\MenuAsset; |
||||||
|
use yii\helpers\Html; |
||||||
|
use yii\helpers\Url; |
||||||
|
use yii\web\JsExpression; |
||||||
|
|
||||||
|
MenuAsset::register($this); |
||||||
|
|
||||||
|
function menu_generate($items) { |
||||||
|
$html = '<ol class="dd-list">'; |
||||||
|
foreach ($items as $item) { |
||||||
|
$html.=Yii::$app->getView()->render( '_item', [ |
||||||
|
'item' => $item, |
||||||
|
] ); |
||||||
|
} |
||||||
|
return $html . '</ol>'; |
||||||
|
} |
||||||
|
|
||||||
|
$url = Url::to(['/menu/save-menu-items']); |
||||||
|
$redirect = Url::to(['menu/index', 'id' => $menu->id]); |
||||||
|
?> |
||||||
|
|
||||||
|
<div class="dd" id="nestable3"> |
||||||
|
<?= menu_generate($items) ?> |
||||||
|
</div> |
||||||
|
|
||||||
|
<!-- |
||||||
|
<div class="dd" id="nestable2"> |
||||||
|
<ol class="dd-list"> |
||||||
|
|
||||||
|
<li class="dd-item dd3-item" data-id="13"> |
||||||
|
<div class="dd3-content"> |
||||||
|
<div class="panel-group" id="accordion"> |
||||||
|
<div class="panel panel-default"> |
||||||
|
<div class="panel-heading"> |
||||||
|
<h4 class="panel-title"> |
||||||
|
<div class="dd-handle dd3-handle"> </div> |
||||||
|
<a data-toggle="collapse" data-parent="#accordion" href="#collapse1">Item 13 |
||||||
|
<i class="fa fa-angle-down pull-right" aria-hidden="true"></i></a> |
||||||
|
</h4> |
||||||
|
</div> |
||||||
|
<div id="collapse1" class="panel-collapse collapse"> |
||||||
|
<div class="panel-body"> |
||||||
|
Content Panel |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</li> |
||||||
|
|
||||||
|
|
||||||
|
<li class="dd-item dd3-item" data-id="14"> |
||||||
|
<div class="dd3-content"> |
||||||
|
<div class="panel-group" id="accordion"> |
||||||
|
<div class="panel panel-default"> |
||||||
|
<div class="panel-heading"> |
||||||
|
<h4 class="panel-title"> |
||||||
|
<div class="dd-handle dd3-handle"> </div> |
||||||
|
<a data-toggle="collapse" data-parent="#accordion" href="#collapse2">Item 14 |
||||||
|
<i class="fa fa-angle-down pull-right" aria-hidden="true"></i></a> |
||||||
|
</h4> |
||||||
|
</div> |
||||||
|
<div id="collapse2" class="panel-collapse collapse"> |
||||||
|
<div class="panel-body"> |
||||||
|
Content Panel |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</li> |
||||||
|
|
||||||
|
<li class="dd-item dd3-item" data-id="15"> |
||||||
|
<div class="dd3-content"> |
||||||
|
<div class="panel-group" id="accordion"> |
||||||
|
<div class="panel panel-default"> |
||||||
|
<div class="panel-heading"> |
||||||
|
<h4 class="panel-title"> |
||||||
|
<div class="dd-handle dd3-handle"> </div> |
||||||
|
<a data-toggle="collapse" data-parent="#accordion" href="#collapse3">Item 15 |
||||||
|
<i class="fa fa-angle-down pull-right" aria-hidden="true"></i></a> |
||||||
|
</h4> |
||||||
|
</div> |
||||||
|
<div id="collapse3" class="panel-collapse collapse"> |
||||||
|
<div class="panel-body"> |
||||||
|
Content Panel |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
|
||||||
|
<ol class="dd-list"> |
||||||
|
<li class="dd-item dd3-item" data-id="16"> |
||||||
|
<div class="dd3-content"> |
||||||
|
<div class="panel-group" id="accordion"> |
||||||
|
<div class="panel panel-default"> |
||||||
|
<div class="panel-heading"> |
||||||
|
<h4 class="panel-title"> |
||||||
|
<div class="dd-handle dd3-handle"> </div> |
||||||
|
<a data-toggle="collapse" data-parent="#accordion" href="#collapse4">Item 16 |
||||||
|
<i class="fa fa-angle-down pull-right" aria-hidden="true"></i></a> |
||||||
|
</h4> |
||||||
|
</div> |
||||||
|
<div id="collapse4" class="panel-collapse collapse"> |
||||||
|
<div class="panel-body"> |
||||||
|
Content Panel |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</li> |
||||||
|
</ol> |
||||||
|
|
||||||
|
</li> |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</ol> |
||||||
|
</div> |
||||||
|
|
||||||
|
</div> |
||||||
|
|
||||||
|
<div style="clear: both;"></div> |
||||||
|
<hr> |
||||||
|
|
||||||
|
<button class="btn btn-primary" id="serialize">Serialize</button> |
||||||
|
<hr> |
||||||
|
<textarea class="form-control" id="output"></textarea> |
||||||
|
|
||||||
|
<hr> |
||||||
|
<textarea class="form-control" id="output2"></textarea> |
||||||
|
--> |
||||||
|
|
||||||
|
<div style="clear: both;"></div> |
||||||
|
<hr> |
||||||
|
|
||||||
|
<?= Html::button(Yii::t('buttons', 'Save'), [ |
||||||
|
'class' => 'btn btn-success pull-right', |
||||||
|
'onclick' => new JsExpression('sendTree('.$menu->id.', "'.$url.'", "'.$redirect.'")'), |
||||||
|
]) ?> |
@ -0,0 +1,195 @@ |
|||||||
|
<?php |
||||||
|
/** |
||||||
|
* Created by Error202 |
||||||
|
* Date: 10.07.2018 |
||||||
|
*/ |
||||||
|
|
||||||
|
namespace backend\controllers; |
||||||
|
|
||||||
|
|
||||||
|
use common\modules\blog\BlogModule; |
||||||
|
use core\entities\menu\Menu; |
||||||
|
use core\entities\menu\MenuItem; |
||||||
|
use core\entities\ModuleRecord; |
||||||
|
use core\forms\menu\MenuForm; |
||||||
|
use core\forms\menu\MenuItemForm; |
||||||
|
use core\forms\menu\MenuSelectForm; |
||||||
|
use core\services\menu\MenuItemManageService; |
||||||
|
use core\services\menu\MenuManageService; |
||||||
|
use yii\filters\AccessControl; |
||||||
|
use yii\filters\VerbFilter; |
||||||
|
use yii\helpers\Json; |
||||||
|
use yii\web\Controller; |
||||||
|
use yii\web\NotFoundHttpException; |
||||||
|
use Yii; |
||||||
|
|
||||||
|
class MenuController extends Controller |
||||||
|
{ |
||||||
|
public $menu_service; |
||||||
|
public $menu_item_service; |
||||||
|
|
||||||
|
public function __construct( string $id, $module, MenuManageService $menu_service, MenuItemManageService $menu_item_service, array $config = [] ) { |
||||||
|
parent::__construct( $id, $module, $config ); |
||||||
|
|
||||||
|
$this->menu_service = $menu_service; |
||||||
|
$this->menu_item_service = $menu_item_service; |
||||||
|
} |
||||||
|
|
||||||
|
public function behaviors(): array |
||||||
|
{ |
||||||
|
return [ |
||||||
|
'access' => [ |
||||||
|
'class' => AccessControl::class, |
||||||
|
'rules' => [ |
||||||
|
[ |
||||||
|
'actions' => ['create', 'update', 'delete', 'index', 'save-menu-items'], |
||||||
|
'allow' => true, |
||||||
|
'roles' => ['MenuManagement'], |
||||||
|
], |
||||||
|
[ // all the action are accessible to admin |
||||||
|
'allow' => true, |
||||||
|
'roles' => ['admin'], |
||||||
|
], |
||||||
|
], |
||||||
|
], |
||||||
|
'verbs' => [ |
||||||
|
'class' => VerbFilter::class, |
||||||
|
'actions' => [ |
||||||
|
'delete' => ['POST'], |
||||||
|
], |
||||||
|
], |
||||||
|
]; |
||||||
|
} |
||||||
|
|
||||||
|
public function actionIndex($id = null) |
||||||
|
{ |
||||||
|
$menus = Menu::find()->all(); |
||||||
|
|
||||||
|
$form = new MenuSelectForm(); |
||||||
|
if ($form->load(Yii::$app->request->get()) && $form->validate()) { |
||||||
|
return $this->redirect(['menu/index', 'id' => $form->id]); |
||||||
|
} |
||||||
|
elseif ($id) { |
||||||
|
$this->createMenuItem(); // create menu item if MenuItemForm sent |
||||||
|
|
||||||
|
$menu = $this->findModel($id); |
||||||
|
|
||||||
|
$creatorWidgets = $this->getCreatorWidgets($menu->id); |
||||||
|
|
||||||
|
return $this->render('menu', [ |
||||||
|
'model' => $form, |
||||||
|
'menus' => $menus, |
||||||
|
'menu' => $menu, |
||||||
|
'creator' => $creatorWidgets, |
||||||
|
]); |
||||||
|
} |
||||||
|
else { |
||||||
|
return $this->render('select_menu', [ |
||||||
|
'model' => $form, |
||||||
|
'menus' => $menus, |
||||||
|
]); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public function actionCreate() |
||||||
|
{ |
||||||
|
$form = new MenuForm(); |
||||||
|
if ($form->load(Yii::$app->request->post()) && $form->validate()) { |
||||||
|
try { |
||||||
|
$menu = $this->menu_service->create($form); |
||||||
|
return $this->redirect(['index', 'id' => $menu->id]); |
||||||
|
} catch (\DomainException $e) { |
||||||
|
Yii::$app->errorHandler->logException($e); |
||||||
|
Yii::$app->session->setFlash('error', $e->getMessage()); |
||||||
|
} |
||||||
|
} |
||||||
|
return $this->render('create', [ |
||||||
|
'model' => $form, |
||||||
|
]); |
||||||
|
} |
||||||
|
|
||||||
|
public function actionUpdate($id) |
||||||
|
{ |
||||||
|
$menu = $this->findModel($id); |
||||||
|
|
||||||
|
$form = new MenuForm($menu); |
||||||
|
if ($form->load(Yii::$app->request->post()) && $form->validate()) { |
||||||
|
try { |
||||||
|
$this->menu_service->edit($menu->id, $form); |
||||||
|
return $this->redirect(['index', 'id' => $menu->id]); |
||||||
|
} catch (\DomainException $e) { |
||||||
|
Yii::$app->errorHandler->logException($e); |
||||||
|
Yii::$app->session->setFlash('error', $e->getMessage()); |
||||||
|
} |
||||||
|
} |
||||||
|
return $this->render('update', [ |
||||||
|
'model' => $form, |
||||||
|
'menu' => $menu, |
||||||
|
]); |
||||||
|
} |
||||||
|
|
||||||
|
public function actionDelete($id) |
||||||
|
{ |
||||||
|
try { |
||||||
|
$this->menu_service->remove($id); |
||||||
|
} catch (\DomainException $e) { |
||||||
|
Yii::$app->errorHandler->logException($e); |
||||||
|
Yii::$app->session->setFlash('error', $e->getMessage()); |
||||||
|
} |
||||||
|
return $this->redirect(['index']); |
||||||
|
} |
||||||
|
|
||||||
|
public function actionSaveMenuItems() |
||||||
|
{ |
||||||
|
$json = Yii::$app->request->post('json'); |
||||||
|
Yii::$app->response->format = \yii\web\Response::FORMAT_JSON; |
||||||
|
if (Yii::$app->request->isAjax) { |
||||||
|
try { |
||||||
|
$order = []; |
||||||
|
$items = Json::decode($json, true); |
||||||
|
foreach ($items as $item) { |
||||||
|
$order[$item[1]] = isset($order[$item[1]]) ? $order[$item[1]]+1 : 0; |
||||||
|
$this->menu_item_service->setPosition($item, $order[$item[1]]); |
||||||
|
} |
||||||
|
return [ 'result' => 'success' ]; |
||||||
|
} |
||||||
|
catch (\RuntimeException $e) { |
||||||
|
return [ 'result' => 'error', 'message' => $e->getMessage() ]; |
||||||
|
} |
||||||
|
} |
||||||
|
return ['result' => 'error', 'message' => 'Request error']; |
||||||
|
} |
||||||
|
|
||||||
|
private function getCreatorWidgets($menu_id): array |
||||||
|
{ |
||||||
|
$widgets = []; |
||||||
|
$modules = ModuleRecord::find()->active()->all(); |
||||||
|
foreach ($modules as $module) { |
||||||
|
if (method_exists($module->class, 'getMenuItemCreator')) { |
||||||
|
$module_widgets = call_user_func_array($module->class . '::getMenuItemCreator', [$menu_id]); |
||||||
|
$widgets = is_array($module_widgets) ? array_merge($widgets, $module_widgets) : $widgets; |
||||||
|
} |
||||||
|
} |
||||||
|
return $widgets; |
||||||
|
} |
||||||
|
|
||||||
|
private function createMenuItem() |
||||||
|
{ |
||||||
|
$form = new MenuItemForm(); |
||||||
|
if ($form->load(Yii::$app->request->post()) && $form->validate()) { |
||||||
|
try { |
||||||
|
$this->menu_item_service->create($form); |
||||||
|
} catch (\DomainException $e) { |
||||||
|
Yii::$app->errorHandler->logException($e); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
protected function findModel($id): Menu |
||||||
|
{ |
||||||
|
if (($model = Menu::findOne($id)) !== null) { |
||||||
|
return $model; |
||||||
|
} |
||||||
|
throw new NotFoundHttpException('The requested menu does not exist.'); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,12 @@ |
|||||||
|
<?php |
||||||
|
return [ |
||||||
|
'Menu' => 'Меню', |
||||||
|
'Select menu...' => 'Укажите меню', |
||||||
|
'Create Menu' => 'Новое меню', |
||||||
|
'Update Menu' => 'Изменить меню', |
||||||
|
'Delete Menu' => 'Удалить меню', |
||||||
|
'Update Menu: {name}' => 'Редактирование меню: {name}', |
||||||
|
'Current Menu' => 'Текущее меню', |
||||||
|
'Available Blocks' => 'Доступные блоки', |
||||||
|
'Menu Items' => 'Элементы меню', |
||||||
|
]; |
@ -0,0 +1,27 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
use yii\helpers\Html; |
||||||
|
use yii\widgets\ActiveForm; |
||||||
|
|
||||||
|
/* @var $this yii\web\View */ |
||||||
|
/* @var $model \core\forms\menu\MenuForm */ |
||||||
|
/* @var $form yii\widgets\ActiveForm */ |
||||||
|
?> |
||||||
|
|
||||||
|
<div class="menu-form"> |
||||||
|
|
||||||
|
<?php $form = ActiveForm::begin(); ?> |
||||||
|
|
||||||
|
<div class="box box-default"> |
||||||
|
<div class="box-body"> |
||||||
|
<?= $form->field($model, 'name')->textInput(['maxlength' => true]) ?> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
|
||||||
|
<div class="form-group"> |
||||||
|
<?= Html::submitButton(Yii::t('buttons', 'Save'), ['class' => 'btn btn-success']) ?> |
||||||
|
</div> |
||||||
|
|
||||||
|
<?php ActiveForm::end(); ?> |
||||||
|
|
||||||
|
</div> |
@ -0,0 +1,16 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
/* @var $this yii\web\View */ |
||||||
|
/* @var $model \core\forms\menu\MenuForm */ |
||||||
|
|
||||||
|
$this->title = Yii::t('menu', 'Create Menu'); |
||||||
|
$this->params['breadcrumbs'][] = ['label' => Yii::t('menu', 'Menu'), 'url' => ['index']]; |
||||||
|
$this->params['breadcrumbs'][] = $this->title; |
||||||
|
?> |
||||||
|
<div class="menu-create"> |
||||||
|
|
||||||
|
<?= $this->render('_form', [ |
||||||
|
'model' => $model, |
||||||
|
]) ?> |
||||||
|
|
||||||
|
</div> |
@ -0,0 +1,114 @@ |
|||||||
|
<?php |
||||||
|
/** |
||||||
|
* Created by Error202 |
||||||
|
* Date: 10.07.2018 |
||||||
|
*/ |
||||||
|
|
||||||
|
use kartik\form\ActiveForm; |
||||||
|
use yii\helpers\ArrayHelper; |
||||||
|
use yii\helpers\Html; |
||||||
|
|
||||||
|
/** |
||||||
|
* @var $this \yii\web\View |
||||||
|
* @var $model \core\forms\menu\MenuSelectForm |
||||||
|
* @var $menus \core\entities\menu\Menu[] |
||||||
|
* @var $menu \core\entities\menu\Menu |
||||||
|
* @var $creator array |
||||||
|
*/ |
||||||
|
|
||||||
|
$this->title = Yii::t('menu', 'Menu'); |
||||||
|
$this->params['breadcrumbs'][] = Html::encode($menu->name); |
||||||
|
$this->params['breadcrumbs'][] = $this->title; |
||||||
|
?> |
||||||
|
|
||||||
|
<div class="menu"> |
||||||
|
<div class="box box-default"> |
||||||
|
<div class="box-header with-border"><?= Yii::t('menu', 'Current Menu') ?></div>
|
||||||
|
<div class="box-body"> |
||||||
|
|
||||||
|
<div class="row"> |
||||||
|
<div class="col-md-6"> |
||||||
|
<?php $form = ActiveForm::begin([ |
||||||
|
'enableClientValidation' => false, |
||||||
|
'method' => 'get', |
||||||
|
'id' => 'select_menu', |
||||||
|
]); ?> |
||||||
|
|
||||||
|
<?= $form->field($model, 'id')->dropDownList(ArrayHelper::map($menus, 'id', 'name'), [ |
||||||
|
//'prompt' => Yii::t('menu', 'Select menu...'), |
||||||
|
'value' => $menu->id, |
||||||
|
'onchange' => 'this.form.submit()', |
||||||
|
])->label(false) ?> |
||||||
|
|
||||||
|
<?php ActiveForm::end(); ?> |
||||||
|
</div> |
||||||
|
<div class="col-md-6"> |
||||||
|
<?= Html::a(Yii::t('menu', 'Create Menu'), ['menu/create'], [ |
||||||
|
'class' => 'btn btn-success', |
||||||
|
]) ?> |
||||||
|
|
||||||
|
<?= Html::a(Yii::t('menu', 'Update Menu'), ['menu/update', 'id' => $menu->id], [ |
||||||
|
'class' => 'btn btn-primary', |
||||||
|
]) ?> |
||||||
|
|
||||||
|
<?= Html::a(Yii::t('menu', 'Delete Menu'), ['menu/delete', 'id' => $menu->id], [ |
||||||
|
'class' => 'btn btn-danger', |
||||||
|
'data' => [ |
||||||
|
'confirm' => Yii::t('buttons', 'Are you sure you want to delete this item?'), |
||||||
|
'method' => 'post', |
||||||
|
], |
||||||
|
]) ?> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
|
||||||
|
</div> |
||||||
|
</div> |
||||||
|
|
||||||
|
<div class="row"> |
||||||
|
<div class="col-md-3"> |
||||||
|
<div class="box box-default"> |
||||||
|
<div class="box-header with-border"><?= Yii::t('menu', 'Available Blocks') ?></div>
|
||||||
|
<div class="box-body"> |
||||||
|
|
||||||
|
<div class="panel-group" id="accordion"> |
||||||
|
|
||||||
|
<?php foreach ($creator as $item): ?> |
||||||
|
|
||||||
|
<div class="panel panel-default"> |
||||||
|
<div class="panel-heading"> |
||||||
|
<h4 class="panel-title"> |
||||||
|
<a data-toggle="collapse" data-parent="#accordion" href="#collapseOne"><?= $item['title'] ?> |
||||||
|
<i class="fa fa-angle-down pull-right" aria-hidden="true"></i></a> |
||||||
|
</h4> |
||||||
|
</div> |
||||||
|
<div id="collapseOne" class="panel-collapse collapse"> |
||||||
|
<div class="panel-body"> |
||||||
|
<?= $item['content'] ?> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
|
||||||
|
<?php endforeach; ?> |
||||||
|
|
||||||
|
</div> |
||||||
|
|
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div class="col-md-9"> |
||||||
|
<div class="box box-default"> |
||||||
|
<div class="box-header with-border"><?= Yii::t('menu', 'Menu Items') ?></div>
|
||||||
|
<div class="box-body"> |
||||||
|
|
||||||
|
<?= \backend\components\menu\widgets\MenuEditorWidget::widget([ |
||||||
|
'menu_id' => $menu->id |
||||||
|
]) ?> |
||||||
|
|
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
|
||||||
|
|
||||||
|
</div> |
||||||
|
|
@ -0,0 +1,51 @@ |
|||||||
|
<?php |
||||||
|
/** |
||||||
|
* Created by Error202 |
||||||
|
* Date: 10.07.2018 |
||||||
|
*/ |
||||||
|
|
||||||
|
use kartik\form\ActiveForm; |
||||||
|
use yii\helpers\ArrayHelper; |
||||||
|
use yii\helpers\Html; |
||||||
|
|
||||||
|
/** |
||||||
|
* @var $this \yii\web\View |
||||||
|
* @var $model \core\forms\menu\MenuSelectForm |
||||||
|
* @var $menus \core\entities\menu\Menu[] |
||||||
|
*/ |
||||||
|
|
||||||
|
$this->title = Yii::t('menu', 'Menu'); |
||||||
|
$this->params['breadcrumbs'][] = $this->title; |
||||||
|
?> |
||||||
|
|
||||||
|
<div class="menu"> |
||||||
|
<div class="box box-default"> |
||||||
|
<div class="box-header with-border"><?= Yii::t('menu', 'Current Menu') ?></div>
|
||||||
|
<div class="box-body"> |
||||||
|
|
||||||
|
<div class="row"> |
||||||
|
<div class="col-md-6"> |
||||||
|
<?php $form = ActiveForm::begin([ |
||||||
|
'enableClientValidation' => false, |
||||||
|
'method' => 'get', |
||||||
|
'id' => 'select_menu', |
||||||
|
]); ?> |
||||||
|
|
||||||
|
<?= $form->field($model, 'id')->dropDownList(ArrayHelper::map($menus, 'id', 'name'), [ |
||||||
|
'prompt' => Yii::t('menu', 'Select menu...'), |
||||||
|
'onchange' => 'this.form.submit()', |
||||||
|
])->label(false) ?> |
||||||
|
|
||||||
|
<?php ActiveForm::end(); ?> |
||||||
|
</div> |
||||||
|
<div class="col-md-2"> |
||||||
|
<?= Html::a(Yii::t('menu', 'Create Menu'), ['menu/create'], [ |
||||||
|
'class' => 'btn btn-success', |
||||||
|
]) ?> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
|
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
|
@ -0,0 +1,18 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
/* @var $this yii\web\View */ |
||||||
|
/* @var $menu \core\entities\menu\Menu */ |
||||||
|
/* @var $model \core\forms\menu\MenuForm */ |
||||||
|
|
||||||
|
$this->title = Yii::t('menu', 'Update Menu: {name}', ['name' => $menu->name]); |
||||||
|
$this->params['breadcrumbs'][] = ['label' => Yii::t('menu', 'Menu'), 'url' => ['index']]; |
||||||
|
$this->params['breadcrumbs'][] = ['label' => $menu->name, 'url' => ['index', 'id' => $menu->id]]; |
||||||
|
$this->params['breadcrumbs'][] = Yii::t('buttons', 'Editing'); |
||||||
|
?> |
||||||
|
<div class="menu-update"> |
||||||
|
|
||||||
|
<?= $this->render('_form', [ |
||||||
|
'model' => $model, |
||||||
|
]) ?> |
||||||
|
|
||||||
|
</div> |
@ -0,0 +1,30 @@ |
|||||||
|
<?php |
||||||
|
/** |
||||||
|
* Created by Error202 |
||||||
|
* Date: 10.07.2018 |
||||||
|
*/ |
||||||
|
|
||||||
|
namespace common\modules\blog\widgets; |
||||||
|
|
||||||
|
|
||||||
|
use core\forms\menu\MenuItemForm; |
||||||
|
use yii\base\Widget; |
||||||
|
|
||||||
|
class MenuItemCreatorWidget extends Widget |
||||||
|
{ |
||||||
|
public $menu_id; |
||||||
|
|
||||||
|
public function run() |
||||||
|
{ |
||||||
|
$form = new MenuItemForm(); |
||||||
|
$form->module = \Yii::t('blog', 'Blog'); |
||||||
|
$form->name = \Yii::t('blog', 'Blog'); |
||||||
|
$form->title_attr = \Yii::t('blog', 'Blog'); |
||||||
|
$form->menu_id = $this->menu_id; |
||||||
|
$form->url = '/blog/post/index'; |
||||||
|
|
||||||
|
return $this->render('menu-item/creator', [ |
||||||
|
'model' => $form, |
||||||
|
]); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,117 @@ |
|||||||
|
<?php |
||||||
|
/** |
||||||
|
* Created by Error202 |
||||||
|
* Date: 10.07.2018 |
||||||
|
*/ |
||||||
|
|
||||||
|
/** |
||||||
|
* @var $this \yii\web\View |
||||||
|
* @var $model \core\forms\menu\MenuItemForm |
||||||
|
*/ |
||||||
|
|
||||||
|
use yii\widgets\ActiveForm; |
||||||
|
use yii\helpers\Html; |
||||||
|
use yii\web\JsExpression; |
||||||
|
use yii\helpers\Url; |
||||||
|
|
||||||
|
$js = <<<JS |
||||||
|
function selectBlogPostOn() { |
||||||
|
$("#post_select").removeAttr('disabled'); |
||||||
|
updateUrl('post') |
||||||
|
} |
||||||
|
|
||||||
|
function selectBlogPostOff() { |
||||||
|
$("#post_select").attr('disabled', 'disabled'); |
||||||
|
updateUrl('blog') |
||||||
|
} |
||||||
|
|
||||||
|
function updateUrl(type) { |
||||||
|
if (type === 'blog') { |
||||||
|
$("#blog_menu_item_url").val('/blog/post/index'); |
||||||
|
$("#blog_menu_item_url_params").val(''); |
||||||
|
} |
||||||
|
else { |
||||||
|
var selected_post = $("#post_select").val(); |
||||||
|
$("#blog_menu_item_url").val('/blog/post/post/'); |
||||||
|
$("#blog_menu_item_url_params").val('{"id":'+selected_post+'}'); |
||||||
|
} |
||||||
|
} |
||||||
|
JS; |
||||||
|
$this->registerJs($js, $this::POS_HEAD); |
||||||
|
|
||||||
|
$fetchUrl = Url::to( [ '/blog/manage/post/post-search' ] ); |
||||||
|
?> |
||||||
|
|
||||||
|
<div class="menu_item_widget"> |
||||||
|
|
||||||
|
<div class="form-group"> |
||||||
|
<div class="radio"> |
||||||
|
<?= Html::label(Html::radio('blog_item_type', true, [ |
||||||
|
'value' => 'blog_home', |
||||||
|
'onclick' => new JsExpression('selectBlogPostOff()'), |
||||||
|
]) . Yii::t('blog', 'Blog Home')) ?> |
||||||
|
</div> |
||||||
|
|
||||||
|
<div class="radio"> |
||||||
|
<?= Html::label(Html::radio('blog_item_type', false, [ |
||||||
|
'value' => 'blog_post', |
||||||
|
'onclick' => new JsExpression('selectBlogPostOn()'), |
||||||
|
]) . Yii::t('blog', 'Blog Post')) ?> |
||||||
|
</div> |
||||||
|
|
||||||
|
<div> |
||||||
|
<?= \kartik\widgets\Select2::widget([ |
||||||
|
'name' => 'post_select', |
||||||
|
'value' => '', |
||||||
|
'options' => [ |
||||||
|
'placeholder' => Yii::t('blog', 'Select post...'), |
||||||
|
'id' => 'post_select', |
||||||
|
'onchange' => new JsExpression("updateUrl('post')"), |
||||||
|
], |
||||||
|
'pluginOptions' => [ |
||||||
|
'disabled' => true, |
||||||
|
'ajax' => [ |
||||||
|
'url' => $fetchUrl, |
||||||
|
'dataType' => 'json', |
||||||
|
'data' => new JsExpression('function(params) { return {q:params.term}; }') |
||||||
|
], |
||||||
|
'escapeMarkup' => new JsExpression('function (markup) { return markup; }'), |
||||||
|
'templateResult' => new JsExpression('function(tag) { return tag.text; }'), |
||||||
|
'templateSelection' => new JsExpression('function (tag) { return tag.text; }'), |
||||||
|
], |
||||||
|
]) ?> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
|
||||||
|
<?php $form = ActiveForm::begin(); ?> |
||||||
|
|
||||||
|
<?= $form->field($model, 'name')->hiddenInput([ |
||||||
|
])->label(false) ?> |
||||||
|
|
||||||
|
<?= $form->field($model, 'title_attr')->hiddenInput([ |
||||||
|
])->label(false) ?> |
||||||
|
|
||||||
|
<?= $form->field($model, 'module')->hiddenInput([ |
||||||
|
])->label(false) ?> |
||||||
|
|
||||||
|
<?= $form->field($model, 'menu_id')->hiddenInput([ |
||||||
|
])->label(false) ?> |
||||||
|
|
||||||
|
<?= $form->field($model, 'url')->hiddenInput([ |
||||||
|
'id' => 'blog_menu_item_url', |
||||||
|
])->label(false) ?> |
||||||
|
|
||||||
|
<?= $form->field($model, 'url_params')->hiddenInput([ |
||||||
|
'value' => '', |
||||||
|
'id' => 'blog_menu_item_url_params', |
||||||
|
])->label(false) ?> |
||||||
|
|
||||||
|
<div class="form-group"> |
||||||
|
<?= Html::submitButton(Yii::t('buttons', 'Add to menu'), [ |
||||||
|
'class' => 'btn btn-info btn-sm pull-right' |
||||||
|
]) ?> |
||||||
|
</div> |
||||||
|
|
||||||
|
<?php ActiveForm::end(); ?> |
||||||
|
|
||||||
|
</div> |
@ -0,0 +1,33 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
use yii\db\Migration; |
||||||
|
|
||||||
|
/** |
||||||
|
* Handles the creation of table `menu`. |
||||||
|
*/ |
||||||
|
class m180709_202649_create_menu_table extends Migration |
||||||
|
{ |
||||||
|
/** |
||||||
|
* {@inheritdoc} |
||||||
|
*/ |
||||||
|
public function safeUp() |
||||||
|
{ |
||||||
|
$tableOptions = null; |
||||||
|
if ($this->db->driverName === 'mysql') { |
||||||
|
$tableOptions = 'CHARACTER SET utf8 COLLATE utf8_general_ci ENGINE=InnoDB'; |
||||||
|
} |
||||||
|
|
||||||
|
$this->createTable('{{%menu}}', [ |
||||||
|
'id' => $this->primaryKey(), |
||||||
|
'name' => $this->string(255)->notNull(), |
||||||
|
], $tableOptions); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* {@inheritdoc} |
||||||
|
*/ |
||||||
|
public function safeDown() |
||||||
|
{ |
||||||
|
$this->dropTable('{{%menu}}'); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,55 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
use yii\db\Migration; |
||||||
|
|
||||||
|
/** |
||||||
|
* Handles the creation of table `menu_items`. |
||||||
|
*/ |
||||||
|
class m180709_202659_create_menu_items_table extends Migration |
||||||
|
{ |
||||||
|
/** |
||||||
|
* {@inheritdoc} |
||||||
|
*/ |
||||||
|
public function safeUp() |
||||||
|
{ |
||||||
|
$tableOptions = null; |
||||||
|
if ($this->db->driverName === 'mysql') { |
||||||
|
$tableOptions = 'CHARACTER SET utf8 COLLATE utf8_general_ci ENGINE=InnoDB'; |
||||||
|
} |
||||||
|
|
||||||
|
$this->createTable('{{%menu_items}}', [ |
||||||
|
'id' => $this->primaryKey(), |
||||||
|
'menu_id' => $this->integer()->notNull(), |
||||||
|
'parent_id' => $this->integer(), |
||||||
|
'name' => $this->string(255)->notNull(), |
||||||
|
'title_attr' => $this->string(255), |
||||||
|
'target' => $this->string(20), |
||||||
|
'css' => $this->string(255), |
||||||
|
'style' => $this->string(255), |
||||||
|
'module' => $this->string(255), |
||||||
|
'url' => $this->string(255), |
||||||
|
'url_params' => $this->text(), // json id=>1, ... |
||||||
|
'sort' => $this->integer()->notNull()->defaultValue(1), |
||||||
|
], $tableOptions); |
||||||
|
|
||||||
|
$this->createIndex('idx_menu_item_sort', '{{%menu_items}}', ['menu_id', 'sort']); |
||||||
|
$this->createIndex('idx_menu_items_menu_id', '{{%menu_items}}', 'menu_id'); |
||||||
|
$this->createIndex('idx_menu_items_parent_id', '{{%menu_items}}', 'parent_id'); |
||||||
|
|
||||||
|
$this->addForeignKey('frg_menu_items_menu_id', '{{%menu_items}}', 'menu_id', '{{%menu}}', 'id', 'CASCADE'); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* {@inheritdoc} |
||||||
|
*/ |
||||||
|
public function safeDown() |
||||||
|
{ |
||||||
|
$this->dropForeignKey('frg_menu_items_menu_id', '{{%menu_items}}'); |
||||||
|
|
||||||
|
$this->dropIndex('idx_menu_items_parent_id', '{{%menu_items}}'); |
||||||
|
$this->dropIndex('idx_menu_items_menu_id', '{{%menu_items}}'); |
||||||
|
$this->dropIndex('idx_menu_item_sort', '{{%menu_items}}'); |
||||||
|
|
||||||
|
$this->dropTable('{{%menu_items}}'); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,44 @@ |
|||||||
|
<?php |
||||||
|
/** |
||||||
|
* Created by Error202 |
||||||
|
* Date: 09.07.2018 |
||||||
|
*/ |
||||||
|
|
||||||
|
namespace core\entities\menu; |
||||||
|
|
||||||
|
use yii\db\ActiveRecord; |
||||||
|
|
||||||
|
/** |
||||||
|
* Class Menu |
||||||
|
* @package core\entities |
||||||
|
* |
||||||
|
* @property integer $id |
||||||
|
* @property string $name |
||||||
|
* |
||||||
|
* @property MenuItem[] $items |
||||||
|
*/ |
||||||
|
|
||||||
|
class Menu extends ActiveRecord |
||||||
|
{ |
||||||
|
public static function create($name): self |
||||||
|
{ |
||||||
|
$menu = new static(); |
||||||
|
$menu->name = $name; |
||||||
|
return $menu; |
||||||
|
} |
||||||
|
|
||||||
|
public function edit($name): void |
||||||
|
{ |
||||||
|
$this->name = $name; |
||||||
|
} |
||||||
|
|
||||||
|
public static function tableName(): string |
||||||
|
{ |
||||||
|
return '{{%menu}}'; |
||||||
|
} |
||||||
|
|
||||||
|
public function getItems() |
||||||
|
{ |
||||||
|
return $this->hasMany(MenuItem::class, ['menu_id' => 'id'])->orderBy(['sort' => SORT_ASC]); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,103 @@ |
|||||||
|
<?php |
||||||
|
/** |
||||||
|
* Created by Error202 |
||||||
|
* Date: 09.07.2018 |
||||||
|
*/ |
||||||
|
|
||||||
|
namespace core\entities\menu; |
||||||
|
|
||||||
|
use paulzi\sortable\SortableBehavior; |
||||||
|
use yii\db\ActiveRecord; |
||||||
|
|
||||||
|
/** |
||||||
|
* Class MenuItem |
||||||
|
* @package core\entities\menu |
||||||
|
* |
||||||
|
* @property integer $id |
||||||
|
* @property integer $menu_id |
||||||
|
* @property integer $parent_id |
||||||
|
* @property string $name |
||||||
|
* @property string $title_attr |
||||||
|
* @property string $target |
||||||
|
* @property string $css |
||||||
|
* @property string $style |
||||||
|
* @property string $module |
||||||
|
* @property string $url |
||||||
|
* @property string $url_params |
||||||
|
* @property integer $sort |
||||||
|
* |
||||||
|
* @property MenuItem $parent |
||||||
|
* @property MenuItem[] $children |
||||||
|
*/ |
||||||
|
|
||||||
|
class MenuItem extends ActiveRecord |
||||||
|
{ |
||||||
|
public static function create($menu_id, $parent_id, $name, $title_attr, $target, $css, $style, $module, $url, $url_params): self |
||||||
|
{ |
||||||
|
$menu = new static(); |
||||||
|
$menu->menu_id = $menu_id; |
||||||
|
$menu->parent_id = $parent_id; |
||||||
|
$menu->name = $name; |
||||||
|
$menu->title_attr = $title_attr; |
||||||
|
$menu->target = $target; |
||||||
|
$menu->css = $css; |
||||||
|
$menu->style = $style; |
||||||
|
$menu->module = $module; |
||||||
|
$menu->url = $url; |
||||||
|
$menu->url_params = $url_params; |
||||||
|
return $menu; |
||||||
|
} |
||||||
|
|
||||||
|
public function edit($menu_id, $parent_id, $name, $title_attr, $target, $css, $style, $module, $url, $url_params): void |
||||||
|
{ |
||||||
|
$this->menu_id = $menu_id; |
||||||
|
$this->parent_id = $parent_id; |
||||||
|
$this->name = $name; |
||||||
|
$this->title_attr = $title_attr; |
||||||
|
$this->target = $target; |
||||||
|
$this->css = $css; |
||||||
|
$this->style = $style; |
||||||
|
$this->module = $module; |
||||||
|
$this->url = $url; |
||||||
|
$this->url_params = $url_params; |
||||||
|
} |
||||||
|
|
||||||
|
public static function tableName(): string |
||||||
|
{ |
||||||
|
return '{{%menu_items}}'; |
||||||
|
} |
||||||
|
|
||||||
|
/*public function behaviors() |
||||||
|
{ |
||||||
|
return [ |
||||||
|
[ |
||||||
|
'class' => SortableBehavior::class, |
||||||
|
'query' => ['menu_id'], |
||||||
|
], |
||||||
|
]; |
||||||
|
}*/ |
||||||
|
|
||||||
|
public function beforeSave( $insert ) { |
||||||
|
if (parent::beforeSave($insert)) { |
||||||
|
if (!isset($this->sort)) { |
||||||
|
$count = MenuItem::find() |
||||||
|
->andWhere( [ 'menu_id' => $this->menu_id ] ) |
||||||
|
->andWhere( [ 'parent_id' => $this->parent_id ] ) |
||||||
|
->count(); |
||||||
|
$this->sort = $count; |
||||||
|
} |
||||||
|
return true; |
||||||
|
} |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
public function getChildren() |
||||||
|
{ |
||||||
|
return $this->hasMany(MenuItem::class, ['parent_id' => 'id'])->orderBy(['sort' => SORT_ASC]); |
||||||
|
} |
||||||
|
|
||||||
|
public function getParent() |
||||||
|
{ |
||||||
|
return $this->hasOne(MenuItem::class, ['id' => 'parent_id']); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,15 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
namespace core\entities\queries; |
||||||
|
|
||||||
|
use yii\db\ActiveQuery; |
||||||
|
|
||||||
|
class ModuleRecordQuery extends ActiveQuery |
||||||
|
{ |
||||||
|
public function active() |
||||||
|
{ |
||||||
|
return $this->andWhere([ |
||||||
|
'active' => 1, |
||||||
|
]); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,37 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
namespace core\forms\menu; |
||||||
|
|
||||||
|
use core\entities\menu\Menu; |
||||||
|
use yii\base\Model; |
||||||
|
use Yii; |
||||||
|
|
||||||
|
class MenuForm extends Model |
||||||
|
{ |
||||||
|
public $name; |
||||||
|
|
||||||
|
private $_menu; |
||||||
|
|
||||||
|
public function __construct(Menu $menu = null, $config = []) |
||||||
|
{ |
||||||
|
if ($menu) { |
||||||
|
$this->name = $menu->name; |
||||||
|
$this->_menu = $menu; |
||||||
|
} |
||||||
|
parent::__construct($config); |
||||||
|
} |
||||||
|
|
||||||
|
public function rules(): array |
||||||
|
{ |
||||||
|
return [ |
||||||
|
[['name'], 'required'], |
||||||
|
[['name'], 'string', 'max' => 255], |
||||||
|
]; |
||||||
|
} |
||||||
|
|
||||||
|
public function attributeLabels() { |
||||||
|
return [ |
||||||
|
'name' => Yii::t('main', 'Name'), |
||||||
|
]; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,68 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
namespace core\forms\menu; |
||||||
|
|
||||||
|
use core\entities\menu\MenuItem; |
||||||
|
use yii\base\Model; |
||||||
|
use Yii; |
||||||
|
|
||||||
|
class MenuItemForm extends Model |
||||||
|
{ |
||||||
|
public $menu_id; |
||||||
|
public $parent_id; |
||||||
|
public $name; |
||||||
|
public $title_attr; |
||||||
|
public $target; |
||||||
|
public $css; |
||||||
|
public $style; |
||||||
|
public $module; |
||||||
|
public $url; |
||||||
|
public $url_params; |
||||||
|
|
||||||
|
private $_menu; |
||||||
|
|
||||||
|
public function __construct(MenuItem $menu = null, $config = []) |
||||||
|
{ |
||||||
|
if ($menu) { |
||||||
|
$this->menu_id = $menu->menu_id; |
||||||
|
$this->parent_id = $menu->parent_id; |
||||||
|
$this->name = $menu->name; |
||||||
|
$this->title_attr = $menu->title_attr; |
||||||
|
$this->target = $menu->target; |
||||||
|
$this->css = $menu->css; |
||||||
|
$this->style = $menu->style; |
||||||
|
$this->module = $menu->module; |
||||||
|
$this->url = $menu->url; |
||||||
|
$this->url_params = $menu->url_params; |
||||||
|
|
||||||
|
$this->_menu = $menu; |
||||||
|
} |
||||||
|
parent::__construct($config); |
||||||
|
} |
||||||
|
|
||||||
|
public function rules(): array |
||||||
|
{ |
||||||
|
return [ |
||||||
|
[['name', 'menu_id', 'url'], 'required'], |
||||||
|
[['name', 'title_attr', 'css', 'style', 'module', 'url'], 'string', 'max' => 255], |
||||||
|
[['target'], 'string', 'max' => 20], |
||||||
|
['url_params', 'string'], |
||||||
|
[['parent_id', 'menu_id'], 'integer'], |
||||||
|
]; |
||||||
|
} |
||||||
|
|
||||||
|
public function attributeLabels() { |
||||||
|
return [ |
||||||
|
'menu_id' => Yii::t('main', 'Menu'), |
||||||
|
'parent id' => Yii::t('main', 'Parent menu item'), |
||||||
|
'name' => Yii::t('main', 'Name'), |
||||||
|
'title_attr' => Yii::t('main', 'Title attribute'), |
||||||
|
'target' => Yii::t('main', 'Target'), |
||||||
|
'css' => Yii::t('main', 'CSS Classes'), |
||||||
|
'style' => Yii::t('main', 'CSS Style'), |
||||||
|
'module' => Yii::t('main', 'Module'), |
||||||
|
'url' => Yii::t('main', 'Url'), |
||||||
|
'url_params' => Yii::t('main', 'Url Params'), |
||||||
|
]; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,25 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
namespace core\forms\menu; |
||||||
|
|
||||||
|
use yii\base\Model; |
||||||
|
use Yii; |
||||||
|
|
||||||
|
class MenuSelectForm extends Model |
||||||
|
{ |
||||||
|
public $id; |
||||||
|
|
||||||
|
public function rules(): array |
||||||
|
{ |
||||||
|
return [ |
||||||
|
[['id'], 'required'], |
||||||
|
[['id'], 'integer'], |
||||||
|
]; |
||||||
|
} |
||||||
|
|
||||||
|
public function attributeLabels() { |
||||||
|
return [ |
||||||
|
'id' => Yii::t('menu', 'Menu'), |
||||||
|
]; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,31 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
namespace core\repositories\menu; |
||||||
|
|
||||||
|
use core\entities\menu\MenuItem; |
||||||
|
use core\repositories\NotFoundException; |
||||||
|
|
||||||
|
class MenuItemRepository |
||||||
|
{ |
||||||
|
public function get($id): MenuItem |
||||||
|
{ |
||||||
|
if (!$item = MenuItem::findOne($id)) { |
||||||
|
throw new NotFoundException('Menu is not found.'); |
||||||
|
} |
||||||
|
return $item; |
||||||
|
} |
||||||
|
|
||||||
|
public function save(MenuItem $item): void |
||||||
|
{ |
||||||
|
if (!$item->save()) { |
||||||
|
throw new \RuntimeException('Saving error.'); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public function remove(MenuItem $item): void |
||||||
|
{ |
||||||
|
if (!$item->delete()) { |
||||||
|
throw new \RuntimeException('Removing error.'); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,31 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
namespace core\repositories\menu; |
||||||
|
|
||||||
|
use core\entities\menu\Menu; |
||||||
|
use core\repositories\NotFoundException; |
||||||
|
|
||||||
|
class MenuRepository |
||||||
|
{ |
||||||
|
public function get($id): Menu |
||||||
|
{ |
||||||
|
if (!$menu = Menu::findOne($id)) { |
||||||
|
throw new NotFoundException('Menu is not found.'); |
||||||
|
} |
||||||
|
return $menu; |
||||||
|
} |
||||||
|
|
||||||
|
public function save(Menu $menu): void |
||||||
|
{ |
||||||
|
if (!$menu->save()) { |
||||||
|
throw new \RuntimeException('Saving error.'); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public function remove(Menu $menu): void |
||||||
|
{ |
||||||
|
if (!$menu->delete()) { |
||||||
|
throw new \RuntimeException('Removing error.'); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,67 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
namespace core\services\menu; |
||||||
|
|
||||||
|
use core\entities\menu\MenuItem; |
||||||
|
use core\forms\menu\MenuItemForm; |
||||||
|
use core\repositories\menu\MenuItemRepository; |
||||||
|
|
||||||
|
class MenuItemManageService |
||||||
|
{ |
||||||
|
private $repository; |
||||||
|
|
||||||
|
public function __construct(MenuItemRepository $repository) |
||||||
|
{ |
||||||
|
$this->repository = $repository; |
||||||
|
} |
||||||
|
|
||||||
|
public function create(MenuItemForm $form): MenuItem |
||||||
|
{ |
||||||
|
$menu = MenuItem::create( |
||||||
|
$form->menu_id, |
||||||
|
$form->parent_id, |
||||||
|
$form->name, |
||||||
|
$form->title_attr, |
||||||
|
$form->target, |
||||||
|
$form->css, |
||||||
|
$form->style, |
||||||
|
$form->module, |
||||||
|
$form->url, |
||||||
|
$form->url_params |
||||||
|
); |
||||||
|
$this->repository->save($menu); |
||||||
|
return $menu; |
||||||
|
} |
||||||
|
|
||||||
|
public function edit($id, MenuItemForm $form): void |
||||||
|
{ |
||||||
|
$menu = $this->repository->get($id); |
||||||
|
$menu->edit( |
||||||
|
$form->menu_id, |
||||||
|
$form->parent_id, |
||||||
|
$form->name, |
||||||
|
$form->title_attr, |
||||||
|
$form->target, |
||||||
|
$form->css, |
||||||
|
$form->style, |
||||||
|
$form->module, |
||||||
|
$form->url, |
||||||
|
$form->url_params |
||||||
|
); |
||||||
|
$this->repository->save($menu); |
||||||
|
} |
||||||
|
|
||||||
|
public function remove($id): void |
||||||
|
{ |
||||||
|
$menu = $this->repository->get($id); |
||||||
|
$this->repository->remove($menu); |
||||||
|
} |
||||||
|
|
||||||
|
public function setPosition(array $position, $sort): void |
||||||
|
{ |
||||||
|
$item = $this->repository->get($position[0]); |
||||||
|
$item->parent_id = $position[1] ? $position[1] : null; |
||||||
|
$item->sort = $sort; |
||||||
|
$this->repository->save($item); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,41 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
namespace core\services\menu; |
||||||
|
|
||||||
|
use core\entities\menu\Menu; |
||||||
|
use core\forms\menu\MenuForm; |
||||||
|
use core\repositories\menu\MenuRepository; |
||||||
|
|
||||||
|
class MenuManageService |
||||||
|
{ |
||||||
|
private $repository; |
||||||
|
|
||||||
|
public function __construct(MenuRepository $repository) |
||||||
|
{ |
||||||
|
$this->repository = $repository; |
||||||
|
} |
||||||
|
|
||||||
|
public function create(MenuForm $form): Menu |
||||||
|
{ |
||||||
|
$menu = Menu::create( |
||||||
|
$form->name |
||||||
|
); |
||||||
|
$this->repository->save($menu); |
||||||
|
return $menu; |
||||||
|
} |
||||||
|
|
||||||
|
public function edit($id, MenuForm $form): void |
||||||
|
{ |
||||||
|
$menu = $this->repository->get($id); |
||||||
|
$menu->edit( |
||||||
|
$form->name |
||||||
|
); |
||||||
|
$this->repository->save($menu); |
||||||
|
} |
||||||
|
|
||||||
|
public function remove($id): void |
||||||
|
{ |
||||||
|
$menu = $this->repository->get($id); |
||||||
|
$this->repository->remove($menu); |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue