Maxymiser task 16
by Vladimir
HTML
<h2>Задание</h2>
<p><strong>Выполнить</strong><br>Реализовать <tt>ContextMenu</tt><br /><u id="menuTarget">Меню тут</u></p>
<ul>
<li>первый аргумент - узел на котором будет работать контекстное меню</li>
<li>второй аргумент - описание структуры меню. Пример описания прикладывается. Структура может быть любой по вложенности и количеству элементов меню. (рекурсивно генерировать DOM будет ок)</li>
<li>подменю может содержать вложенные подменю</li>
<li>при правом клике по узлу, для которого было создано ContextMenu показывать меню прямо под местом клика.</li>
<li>при клике по пункту меню должна выполняться соответствующая функция</li>
<li>каждый элемент, содержащий подменю, должен быть отмечен ">" символом</li>
<li>подменю открывается при наведении на пункт подменю, и закрывается при уходе мышки с подменю или пункта подменю (смотри события mouseenter и mouseleave)</li>
<li>с позиционированием (чтобы все меню и подменю вмещались в видимую часть экрана) можно не заморачиваться</li>
<li>стилизовать меню можно на свой вкус (главное - видимые границы элементов)</li>
</ul>
<code>var menuExample = [{
title: 'File',
action: function () {console.log('open file')}
}, {
title: 'Edit',
action: function () {console.log('edit content')}
}, {
title: 'More stuff',
submenu: [{
title: 'Send by email',
action: function () {console.log('emailed')}
}, {
title: 'Send via skype',
action: function () {console.log('skyped')}
}]
}]</code>
CSS
body {
font-family: Verdana, sans-serif;
}
code {
display: block;
background: #EEE;
white-space: pre;
padding: 5px;
}
.context-menu,
.submenu {
-webkit-box-shadow: 0 0 6px 1px #EEE;
-moz-box-shadow: 0 0 6px 1px #EEE;
box-shadow: 0 0 6px 1px #EEE;
padding: 0px;
list-style: none;
position: absolute;
display: none;
background: #EEE;
font-family: 'Lucida Console', Courier,monospace;
}
.context-menu li {
cursor:pointer;
padding: 3px;
height:14px;
line-height: 14px;
width: 150px;
position: relative;
}
.context-menu li:hover {
background: #CCC;
}
.context-menu li.have-items:after {
content: '>';
display: block;
right: 2px;
position: absolute;
top: 2px;
}
.submenu {
left: 100%;
margin: -20px 0 0;
}
JavaScript
//* Cross-browser adding events
var addEvent, removeEvent;
if (document.addEventListener) { // проверка существования метода
addEvent = function(elem, type, handler) {
elem.addEventListener(type, handler, false);
};
removeEvent = function(elem, type, handler) {
elem.removeEventListener(type, handler, false);
};
} else {
addEvent = function(elem, type, handler) {
elem.attachEvent("on" + type, handler);
};
removeEvent = function(elem, type, handler) {
elem.detachEvent("on" + type, handler);
};
}
var menuDom;
var subMenus = [];
function ContextMenu(el, struct) {
menuDom = document.createElement('ul');
menuDom.className = 'context-menu';
var subLevels = [];
for(var i in struct) {
var menuItem = document.createElement('li');
var menuItemTitle = document.createTextNode(struct[i].title);
menuItem.appendChild(menuItemTitle);
if('action' in struct[i]) {
// simple item
addEvent(menuItem, 'click', struct[i].action);
} else {
// item with submenu
menuItem.className = 'have-items';
subMenus.push(buildSubmenu(struct[i].submenu));
menuItem.appendChild(subMenus[subMenus.length-1]);
addEvent(menuItem, 'mouseover', function() {
this.children[0].style.display = 'block';
});
addEvent(menuItem, 'mouseout', function() {
this.children[0].style.display = 'none';
});
}
menuDom.appendChild(menuItem);
}
document.body.appendChild(menuDom);
addEvent(el, 'contextmenu', function(e) {
var ev = e || window.event;
ev.stopPropagation();
ev.preventDefault();
menuDom.style.display = 'block';
menuDom.style.left = ev.pageX + 'px';
menuDom.style.top = ev.pageY + 'px';
});
addEvent(document.body, 'click', menuHide);
}
//* NEED MORE REFACTORING
function buildSubmenu(submenu) {
var subMenuDom = document.createElement('ul');
subMenuDom.className = 'submenu';
for(var i = 0; i < submenu.length; i++) {
var subMenuItem =...