2021-02-20 17:31:36 +08:00
|
|
|
var open_menu = null;
|
2021-01-11 06:57:55 +08:00
|
|
|
|
|
|
|
function handleMenuOverflow(node) {
|
|
|
|
node = node.get(0);
|
|
|
|
if (!node) return;
|
|
|
|
// Todo: mobile support
|
|
|
|
node.addEventListener('wheel', e => {
|
|
|
|
e.stopPropagation();
|
|
|
|
let top = parseInt(node.style.top);
|
|
|
|
let offset = top - $(node).offset().top;
|
|
|
|
top = Math.clamp(
|
|
|
|
top - e.deltaY,
|
|
|
|
window.innerHeight - node.clientHeight + offset,
|
|
|
|
offset + 26
|
|
|
|
);
|
|
|
|
node.style.top = `${top}px`;
|
|
|
|
})
|
|
|
|
}
|
2019-07-18 00:02:07 +08:00
|
|
|
class Menu {
|
|
|
|
constructor(structure) {
|
|
|
|
this.children = [];
|
|
|
|
this.node = $('<ul class="contextMenu"></ul>')[0]
|
|
|
|
this.structure = structure
|
|
|
|
}
|
|
|
|
hover(node, event) {
|
|
|
|
if (event) event.stopPropagation()
|
|
|
|
$(open_menu.node).find('li.focused').removeClass('focused')
|
|
|
|
$(open_menu.node).find('li.opened').removeClass('opened')
|
|
|
|
var obj = $(node)
|
|
|
|
obj.addClass('focused')
|
|
|
|
obj.parents('li.parent').addClass('opened')
|
|
|
|
|
|
|
|
if (obj.hasClass('parent')) {
|
|
|
|
var childlist = obj.find('> ul.contextMenu.sub')
|
|
|
|
|
|
|
|
var p_width = obj.outerWidth()
|
|
|
|
childlist.css('left', p_width + 'px')
|
|
|
|
var el_width = childlist.width()
|
|
|
|
var offset = childlist.offset()
|
|
|
|
var el_height = childlist.height()
|
|
|
|
|
2021-01-31 07:12:53 +08:00
|
|
|
if (offset.left + el_width > window.innerWidth) {
|
2019-07-18 00:02:07 +08:00
|
|
|
if (Blockbench.isMobile) {
|
|
|
|
childlist.css('visibility', 'hidden');
|
|
|
|
setTimeout(() => {
|
|
|
|
childlist.css('left', 0);
|
|
|
|
childlist.css('visibility', 'visible');
|
|
|
|
}, 100);
|
|
|
|
} else {
|
|
|
|
childlist.css('left', -el_width + 'px')
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-11 06:57:55 +08:00
|
|
|
let window_height = window.innerHeight - 26;
|
|
|
|
|
|
|
|
if (el_height > window_height) {
|
|
|
|
childlist.css('margin-top', '0').css('top', '0')
|
|
|
|
childlist.css('top', (-childlist.offset().top + 26) + 'px')
|
|
|
|
handleMenuOverflow(childlist);
|
2020-07-18 03:49:23 +08:00
|
|
|
|
2021-01-11 06:57:55 +08:00
|
|
|
} else if (offset.top + el_height > window_height) {
|
|
|
|
childlist.css('margin-top', 26-childlist.height() + 'px')
|
2020-07-18 03:49:23 +08:00
|
|
|
if (childlist.offset().top < 26) {
|
|
|
|
childlist.offset({top: 26})
|
2019-07-18 00:02:07 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
keyNavigate(e) {
|
|
|
|
var scope = this;
|
|
|
|
var used;
|
|
|
|
var obj = $(this.node)
|
|
|
|
if (e.which >= 37 && e.which <= 40) {
|
|
|
|
|
2021-03-02 02:38:10 +08:00
|
|
|
let is_menu_bar = scope.type === 'bar_menu' && e.which%2;
|
|
|
|
if (obj.find('li.focused').length || is_menu_bar) {
|
2019-07-18 00:02:07 +08:00
|
|
|
var old = obj.find('li.focused'), next;
|
|
|
|
switch (e.which) {
|
|
|
|
case 37: next = old.parent('ul').parent('li'); break;//<
|
|
|
|
case 38: next = old.prevAll('li:not(.menu_separator)').first(); break;//UP
|
|
|
|
case 39: next = old.find('ul li:first-child'); break;//>
|
|
|
|
case 40: next = old.nextAll('li:not(.menu_separator)').first(); break;//DOWN
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!next.length && e.which%2 == 0) {
|
|
|
|
var siblings = old.siblings('li:not(.menu_separator)')
|
|
|
|
if (e.which === 38) {
|
|
|
|
next = siblings.last()
|
|
|
|
} else {
|
|
|
|
next = siblings.first()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (next && next.length) {
|
|
|
|
old.removeClass('focused')
|
|
|
|
scope.hover(next.get(0))
|
2021-03-02 02:38:10 +08:00
|
|
|
} else if (is_menu_bar) {
|
2019-07-18 00:02:07 +08:00
|
|
|
var index = MenuBar.keys.indexOf(scope.id)
|
|
|
|
index += (e.which == 39 ? 1 : -1)
|
|
|
|
if (index < 0) {
|
|
|
|
index = MenuBar.keys.length-1
|
|
|
|
} else if (index >= MenuBar.keys.length) {
|
|
|
|
index = 0;
|
|
|
|
}
|
2020-04-26 02:25:07 +08:00
|
|
|
MenuBar.menus[MenuBar.keys[index]].open()
|
2019-07-18 00:02:07 +08:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
obj.find('> li:first-child').addClass('focused')
|
|
|
|
}
|
|
|
|
used = true;
|
|
|
|
} else if (Keybinds.extra.confirm.keybind.isTriggered(e)) {
|
|
|
|
obj.find('li.focused').click()
|
|
|
|
if (scope) {
|
|
|
|
scope.hide()
|
|
|
|
}
|
|
|
|
used = true;
|
|
|
|
} else if (Keybinds.extra.cancel.keybind.isTriggered(e)) {
|
|
|
|
scope.hide()
|
|
|
|
used = true;
|
|
|
|
}
|
|
|
|
return used;
|
|
|
|
}
|
|
|
|
open(position, context) {
|
|
|
|
|
2020-01-24 01:53:36 +08:00
|
|
|
if (position && position.changedTouches) {
|
2019-12-16 03:04:31 +08:00
|
|
|
convertTouchEvent(position);
|
|
|
|
}
|
2019-07-18 00:02:07 +08:00
|
|
|
var scope = this;
|
|
|
|
var ctxmenu = $(this.node)
|
|
|
|
if (open_menu) {
|
|
|
|
open_menu.hide()
|
|
|
|
}
|
|
|
|
$('body').append(ctxmenu)
|
|
|
|
|
|
|
|
ctxmenu.children().detach()
|
|
|
|
|
2020-04-26 02:25:07 +08:00
|
|
|
function createChildList(object, node) {
|
|
|
|
|
|
|
|
if (typeof object.children == 'function') {
|
|
|
|
var list = object.children(context)
|
|
|
|
} else {
|
|
|
|
var list = object.children
|
|
|
|
}
|
|
|
|
if (list.length) {
|
|
|
|
node.addClass('parent')
|
|
|
|
.find('ul.contextMenu.sub').detach()
|
|
|
|
var childlist = $('<ul class="contextMenu sub"></ul>')
|
|
|
|
node.append(childlist)
|
|
|
|
list.forEach(function(s2, i) {
|
|
|
|
getEntry(s2, childlist)
|
|
|
|
})
|
|
|
|
var last = childlist.children().last()
|
|
|
|
if (last.length && last.hasClass('menu_separator')) {
|
|
|
|
last.remove()
|
|
|
|
}
|
|
|
|
return childlist.children().length;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-07-18 00:02:07 +08:00
|
|
|
function getEntry(s, parent) {
|
|
|
|
|
|
|
|
var entry;
|
|
|
|
if (s === '_') {
|
|
|
|
entry = new MenuSeparator().menu_node
|
|
|
|
var last = parent.children().last()
|
|
|
|
if (last.length && !last.hasClass('menu_separator')) {
|
|
|
|
parent.append(entry)
|
|
|
|
}
|
2020-09-27 16:01:39 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (typeof s == 'string' && BarItems[s]) {
|
|
|
|
s = BarItems[s];
|
|
|
|
}
|
|
|
|
if (!Condition(s.condition, context)) return;
|
|
|
|
|
|
|
|
if (s instanceof Action) {
|
|
|
|
|
|
|
|
entry = $(s.menu_node)
|
|
|
|
|
2021-03-02 02:38:10 +08:00
|
|
|
entry.removeClass('focused')
|
2020-09-27 16:01:39 +08:00
|
|
|
entry.off('click')
|
|
|
|
entry.off('mouseenter mousedown')
|
|
|
|
entry.on('mouseenter mousedown', function(e) {
|
|
|
|
if (this == e.target) {
|
|
|
|
scope.hover(this, e)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
//Submenu
|
|
|
|
if (typeof s.children == 'function' || typeof s.children == 'object') {
|
|
|
|
createChildList(s, entry)
|
|
|
|
} else {
|
|
|
|
entry.on('click', (e) => {s.trigger(e)})
|
2019-07-18 00:02:07 +08:00
|
|
|
}
|
2021-05-23 02:19:41 +08:00
|
|
|
|
2020-09-27 16:01:39 +08:00
|
|
|
parent.append(entry)
|
|
|
|
|
|
|
|
} else if (s instanceof BarSelect) {
|
|
|
|
|
|
|
|
if (typeof s.icon === 'function') {
|
|
|
|
var icon = Blockbench.getIconNode(s.icon(context), s.color)
|
|
|
|
} else {
|
|
|
|
var icon = Blockbench.getIconNode(s.icon, s.color)
|
2019-07-18 00:02:07 +08:00
|
|
|
}
|
2021-06-24 23:48:25 +08:00
|
|
|
entry = $(`<li title="${s.description ? tl(s.description) : ''}" menu_item="${s.id}"><span>${tl(s.name)}</span></li>`)
|
2020-09-27 16:01:39 +08:00
|
|
|
entry.prepend(icon)
|
2019-07-18 00:02:07 +08:00
|
|
|
|
2020-09-27 16:01:39 +08:00
|
|
|
//Submenu
|
|
|
|
var children = [];
|
|
|
|
for (var key in s.options) {
|
|
|
|
|
|
|
|
let val = s.options[key];
|
|
|
|
if (val) {
|
|
|
|
(function() {
|
|
|
|
var save_key = key;
|
|
|
|
children.push({
|
|
|
|
name: s.getNameFor(key),
|
|
|
|
id: key,
|
|
|
|
icon: val.icon || ((s.value == save_key) ? 'far.fa-dot-circle' : 'far.fa-circle'),
|
|
|
|
condition: val.condition,
|
|
|
|
click: (e) => {
|
|
|
|
s.set(save_key);
|
|
|
|
if (s.onChange) {
|
|
|
|
s.onChange(s, e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
})()
|
2019-07-18 00:02:07 +08:00
|
|
|
}
|
2020-09-27 16:01:39 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
let child_count = createChildList({children}, entry)
|
|
|
|
|
|
|
|
if (child_count !== 0 || typeof s.click === 'function') {
|
2019-07-18 00:02:07 +08:00
|
|
|
parent.append(entry)
|
|
|
|
}
|
2020-09-27 16:01:39 +08:00
|
|
|
entry.mouseenter(function(e) {
|
|
|
|
scope.hover(this, e)
|
|
|
|
})
|
|
|
|
|
2019-07-18 00:02:07 +08:00
|
|
|
} else if (typeof s === 'object') {
|
2020-04-30 05:35:47 +08:00
|
|
|
|
2020-09-27 16:01:39 +08:00
|
|
|
let child_count;
|
|
|
|
if (typeof s.icon === 'function') {
|
|
|
|
var icon = Blockbench.getIconNode(s.icon(context), s.color)
|
|
|
|
} else {
|
|
|
|
var icon = Blockbench.getIconNode(s.icon, s.color)
|
|
|
|
}
|
2021-06-24 23:48:25 +08:00
|
|
|
entry = $(`<li title="${s.description ? tl(s.description) : ''}" menu_item="${s.id}"><span>${tl(s.name)}</span></li>`)
|
2020-09-27 16:01:39 +08:00
|
|
|
entry.prepend(icon)
|
|
|
|
if (typeof s.click === 'function') {
|
|
|
|
entry.click(e => {
|
|
|
|
if (e.target == entry.get(0)) {
|
|
|
|
s.click(context, e)
|
|
|
|
}
|
2019-07-18 00:02:07 +08:00
|
|
|
})
|
|
|
|
}
|
2020-09-27 16:01:39 +08:00
|
|
|
//Submenu
|
|
|
|
if (typeof s.children == 'function' || typeof s.children == 'object') {
|
|
|
|
child_count = createChildList(s, entry)
|
|
|
|
}
|
|
|
|
if (child_count !== 0 || typeof s.click === 'function') {
|
|
|
|
parent.append(entry)
|
|
|
|
}
|
|
|
|
entry.mouseenter(function(e) {
|
|
|
|
scope.hover(this, e)
|
|
|
|
})
|
2019-07-18 00:02:07 +08:00
|
|
|
}
|
2021-05-23 02:19:41 +08:00
|
|
|
//Highlight
|
|
|
|
if (scope.highlight_action == s && entry) {
|
|
|
|
let obj = entry;
|
|
|
|
while (obj[0] && obj[0].nodeName == 'LI') {
|
|
|
|
obj.addClass('highlighted');
|
|
|
|
obj = obj.parent().parent();
|
|
|
|
}
|
|
|
|
}
|
2019-07-18 00:02:07 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
scope.structure.forEach(function(s, i) {
|
|
|
|
getEntry(s, ctxmenu)
|
|
|
|
})
|
|
|
|
var last = ctxmenu.children().last()
|
|
|
|
if (last.length && last.hasClass('menu_separator')) {
|
|
|
|
last.remove()
|
|
|
|
}
|
|
|
|
|
|
|
|
var el_width = ctxmenu.width()
|
|
|
|
var el_height = ctxmenu.height()
|
2021-01-11 06:57:55 +08:00
|
|
|
let window_height = window.innerHeight - 26;
|
2019-07-18 00:02:07 +08:00
|
|
|
|
|
|
|
if (position && position.clientX !== undefined) {
|
|
|
|
var offset_left = position.clientX
|
|
|
|
var offset_top = position.clientY+1
|
2020-04-26 02:25:07 +08:00
|
|
|
|
|
|
|
} else if (position == document.body) {
|
|
|
|
var offset_left = (document.body.clientWidth-el_width)/2
|
|
|
|
var offset_top = (document.body.clientHeight-el_height)/2
|
|
|
|
|
2019-07-18 00:02:07 +08:00
|
|
|
} else {
|
|
|
|
if (!position && scope.type === 'bar_menu') {
|
|
|
|
position = scope.label
|
2020-09-30 23:29:13 +08:00
|
|
|
} else if (position && position.parentElement.classList.contains('tool')) {
|
|
|
|
position = position.parentElement;
|
2019-07-18 00:02:07 +08:00
|
|
|
}
|
|
|
|
var offset_left = $(position).offset().left;
|
2021-05-29 05:42:35 +08:00
|
|
|
var offset_top = $(position).offset().top + position.clientHeight;
|
2019-07-18 00:02:07 +08:00
|
|
|
}
|
|
|
|
|
2021-01-31 07:12:53 +08:00
|
|
|
if (offset_left > window.innerWidth - el_width) {
|
2019-07-18 00:02:07 +08:00
|
|
|
offset_left -= el_width
|
2020-03-15 04:32:24 +08:00
|
|
|
if (position && position.clientWidth) offset_left += position.clientWidth;
|
2019-07-18 00:02:07 +08:00
|
|
|
}
|
2020-07-18 03:49:23 +08:00
|
|
|
if (offset_top > window_height - el_height ) {
|
2021-05-29 05:42:35 +08:00
|
|
|
offset_top -= el_height;
|
|
|
|
if (position instanceof HTMLElement) {
|
|
|
|
offset_top -= position.clientHeight;
|
|
|
|
}
|
2019-07-18 00:02:07 +08:00
|
|
|
}
|
2020-07-18 03:49:23 +08:00
|
|
|
offset_top = Math.clamp(offset_top, 26)
|
2019-07-18 00:02:07 +08:00
|
|
|
|
|
|
|
ctxmenu.css('left', offset_left+'px')
|
|
|
|
ctxmenu.css('top', offset_top +'px')
|
|
|
|
|
2020-07-18 03:49:23 +08:00
|
|
|
if (el_height > window_height) {
|
2021-01-11 06:57:55 +08:00
|
|
|
handleMenuOverflow(ctxmenu);
|
2020-07-18 03:49:23 +08:00
|
|
|
}
|
|
|
|
|
2021-05-29 05:42:35 +08:00
|
|
|
$(scope.node).on('click', (ev) => {
|
|
|
|
if (
|
|
|
|
ev.target.className.includes('parent') ||
|
|
|
|
(ev.target.parentNode && ev.target.parentNode.className.includes('parent'))
|
|
|
|
) {} else {
|
|
|
|
scope.hide()
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
2019-07-18 00:02:07 +08:00
|
|
|
if (scope.type === 'bar_menu') {
|
|
|
|
MenuBar.open = scope
|
|
|
|
$(scope.label).addClass('opened')
|
|
|
|
}
|
|
|
|
open_menu = scope;
|
|
|
|
return scope;
|
|
|
|
}
|
|
|
|
show(position) {
|
|
|
|
return this.open(position);
|
|
|
|
}
|
|
|
|
hide() {
|
2021-05-23 02:19:41 +08:00
|
|
|
$(this.node).find('li.highlighted').removeClass('highlighted');
|
2019-07-18 00:02:07 +08:00
|
|
|
$(this.node).detach()
|
2021-02-20 17:31:36 +08:00
|
|
|
open_menu = null;
|
2019-07-18 00:02:07 +08:00
|
|
|
return this;
|
|
|
|
}
|
|
|
|
conditionMet() {
|
2021-01-27 05:46:17 +08:00
|
|
|
return Condition(this.condition);
|
2019-07-18 00:02:07 +08:00
|
|
|
}
|
|
|
|
addAction(action, path) {
|
|
|
|
|
|
|
|
if (path === undefined) path = ''
|
|
|
|
var track = path.split('.')
|
|
|
|
|
|
|
|
function traverse(arr, layer) {
|
|
|
|
if (track.length === layer || track[layer] === '' || !isNaN(parseInt(track[layer]))) {
|
|
|
|
var index = arr.length;
|
|
|
|
if (track[layer] !== '' && track.length !== layer) {
|
|
|
|
index = parseInt(track[layer])
|
|
|
|
}
|
|
|
|
arr.splice(index, 0, action)
|
|
|
|
} else {
|
|
|
|
for (var i = 0; i < arr.length; i++) {
|
|
|
|
var item = arr[i]
|
|
|
|
if (item.children && item.children.length > 0 && item.id === track[layer] && layer < 20) {
|
|
|
|
traverse(item.children, layer+1)
|
|
|
|
i = 1000
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
traverse(this.structure, 0)
|
|
|
|
if (action && action.menus) {
|
|
|
|
action.menus.push({menu: this, path});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
removeAction(path) {
|
|
|
|
var scope = this;
|
|
|
|
if (path === undefined) path = ''
|
|
|
|
path = path.split('.')
|
|
|
|
|
|
|
|
function traverse(arr, layer) {
|
|
|
|
var result;
|
|
|
|
if (!isNaN(parseInt(path[layer]))) {
|
|
|
|
result = arr[parseInt(path[layer])]
|
|
|
|
|
|
|
|
} else if (typeof path[layer] === 'string') {
|
|
|
|
var i = arr.length-1;
|
|
|
|
while (i >= 0) {
|
|
|
|
var item = arr[i]
|
|
|
|
if (item.id === path[layer] && layer < 20) {
|
|
|
|
if (layer === path.length-1) {
|
|
|
|
var action = arr.splice(i, 1)[0]
|
|
|
|
if (action instanceof Action) {
|
|
|
|
for (var i = action.menus.length-1; i >= 0; i--) {
|
|
|
|
if (action.menus[i].menu == scope) {
|
|
|
|
action.menus.splice(i, 1)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (item.children) {
|
|
|
|
traverse(item.children, layer+1)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
i--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
traverse(this.structure, 0)
|
|
|
|
}
|
2020-03-05 03:56:17 +08:00
|
|
|
deleteItem(rm_item) {
|
|
|
|
var scope = this;
|
|
|
|
|
|
|
|
function traverse(arr, layer) {
|
|
|
|
arr.forEachReverse((item, i) => {
|
|
|
|
if (item === rm_item || item === rm_item.id) {
|
|
|
|
arr.splice(i, 1)
|
|
|
|
} else if (item && item.children instanceof Array) {
|
|
|
|
traverse(item.children)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
traverse(this.structure, 0)
|
|
|
|
rm_item.menus.remove(scope)
|
|
|
|
}
|
2019-07-18 00:02:07 +08:00
|
|
|
}
|
|
|
|
class BarMenu extends Menu {
|
2021-01-27 05:46:17 +08:00
|
|
|
constructor(id, structure, options = {}) {
|
2019-07-18 00:02:07 +08:00
|
|
|
super()
|
|
|
|
var scope = this;
|
2020-04-26 02:25:07 +08:00
|
|
|
MenuBar.menus[id] = this
|
2019-07-18 00:02:07 +08:00
|
|
|
this.type = 'bar_menu'
|
|
|
|
this.id = id
|
|
|
|
this.children = [];
|
2021-01-27 05:46:17 +08:00
|
|
|
this.condition = options.condition
|
2019-07-18 00:02:07 +08:00
|
|
|
this.node = $('<ul class="contextMenu"></ul>')[0]
|
2021-09-08 00:19:39 +08:00
|
|
|
this.node.style.minHeight = '8px';
|
|
|
|
this.node.style.minWidth = '150px';
|
2021-01-27 05:46:17 +08:00
|
|
|
this.name = tl(options.name || `menu.${id}`);
|
|
|
|
this.label = $(`<li class="menu_bar_point">${this.name}</li>`)[0]
|
2019-07-18 00:02:07 +08:00
|
|
|
$(this.label).click(function() {
|
|
|
|
if (open_menu === scope) {
|
|
|
|
scope.hide()
|
|
|
|
} else {
|
|
|
|
scope.open()
|
|
|
|
}
|
|
|
|
})
|
|
|
|
$(this.label).mouseenter(function() {
|
|
|
|
if (MenuBar.open && MenuBar.open !== scope) {
|
|
|
|
scope.open()
|
|
|
|
}
|
|
|
|
})
|
2021-05-23 02:19:41 +08:00
|
|
|
this.structure = structure;
|
|
|
|
this.highlight_action = null;
|
2019-07-18 00:02:07 +08:00
|
|
|
}
|
|
|
|
hide() {
|
2021-05-23 02:19:41 +08:00
|
|
|
super.hide();
|
|
|
|
$(this.label).removeClass('opened');
|
|
|
|
MenuBar.open = undefined;
|
|
|
|
this.highlight_action = null;
|
|
|
|
this.label.classList.remove('highlighted');
|
2019-07-18 00:02:07 +08:00
|
|
|
return this;
|
|
|
|
}
|
2021-05-23 02:19:41 +08:00
|
|
|
highlight(action) {
|
|
|
|
this.highlight_action = action;
|
|
|
|
this.label.classList.add('highlighted');
|
|
|
|
}
|
2019-07-18 00:02:07 +08:00
|
|
|
}
|
|
|
|
const MenuBar = {
|
2020-04-26 02:25:07 +08:00
|
|
|
menus: {},
|
2019-07-18 00:02:07 +08:00
|
|
|
open: undefined,
|
|
|
|
setup() {
|
2020-04-26 02:25:07 +08:00
|
|
|
MenuBar.menues = MenuBar.menus;
|
2019-07-18 00:02:07 +08:00
|
|
|
new BarMenu('file', [
|
|
|
|
'project_window',
|
|
|
|
'_',
|
|
|
|
{name: 'menu.file.new', id: 'new', icon: 'insert_drive_file',
|
|
|
|
children: function() {
|
|
|
|
var arr = [];
|
|
|
|
for (var key in Formats) {
|
|
|
|
(function() {
|
|
|
|
var format = Formats[key];
|
|
|
|
arr.push({
|
|
|
|
id: format.id,
|
|
|
|
name: format.name,
|
|
|
|
icon: format.icon,
|
|
|
|
description: format.description,
|
|
|
|
click: (e) => {
|
2019-07-26 19:33:29 +08:00
|
|
|
format.new()
|
2019-07-18 00:02:07 +08:00
|
|
|
}
|
|
|
|
})
|
|
|
|
})()
|
|
|
|
}
|
|
|
|
return arr;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
{name: 'menu.file.recent', id: 'recent', icon: 'history',
|
2021-07-24 19:51:42 +08:00
|
|
|
condition: function() {return isApp && recent_projects.length},
|
2019-07-18 00:02:07 +08:00
|
|
|
children: function() {
|
|
|
|
var arr = []
|
2020-07-16 15:32:59 +08:00
|
|
|
let redact = settings.streamer_mode.value;
|
2019-07-18 00:02:07 +08:00
|
|
|
recent_projects.forEach(function(p) {
|
|
|
|
arr.push({
|
2020-07-16 15:32:59 +08:00
|
|
|
name: redact ? `[${tl('generic.redacted')}]` : p.name,
|
2019-07-18 00:02:07 +08:00
|
|
|
path: p.path,
|
2020-07-16 15:32:59 +08:00
|
|
|
description: redact ? '' : p.path,
|
2019-07-18 00:02:07 +08:00
|
|
|
icon: p.icon,
|
|
|
|
click: function(c, event) {
|
|
|
|
Blockbench.read([p.path], {}, files => {
|
|
|
|
loadModelFile(files[0]);
|
|
|
|
})
|
|
|
|
}
|
|
|
|
})
|
|
|
|
})
|
2020-11-25 16:51:17 +08:00
|
|
|
if (arr.length) {
|
|
|
|
arr.push('_', {
|
|
|
|
name: 'menu.file.recent.clear',
|
|
|
|
icon: 'clear',
|
|
|
|
click: function(c, event) {
|
|
|
|
recent_projects.empty();
|
|
|
|
updateRecentProjects();
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
2019-07-18 00:02:07 +08:00
|
|
|
return arr
|
|
|
|
}
|
|
|
|
},
|
|
|
|
'open_model',
|
2021-08-18 05:28:15 +08:00
|
|
|
'open_from_link',
|
2020-07-16 15:32:59 +08:00
|
|
|
'_',
|
2019-07-18 00:02:07 +08:00
|
|
|
'save_project',
|
|
|
|
'save_project_as',
|
|
|
|
'convert_project',
|
|
|
|
'close_project',
|
|
|
|
'_',
|
|
|
|
{name: 'menu.file.import', id: 'import', icon: 'insert_drive_file', children: [
|
2021-09-22 19:47:46 +08:00
|
|
|
{
|
|
|
|
id: 'import_open_project',
|
|
|
|
name: 'menu.file.import.import_open_project',
|
|
|
|
icon: 'input',
|
|
|
|
condition: () => Project && ModelProject.all.length > 1,
|
|
|
|
children() {
|
|
|
|
let projects = [];
|
|
|
|
ModelProject.all.forEach(project => {
|
|
|
|
if (project == Project) return;
|
|
|
|
projects.push({
|
|
|
|
name: project.getDisplayName(),
|
|
|
|
icon: project.format.icon,
|
|
|
|
description: project.path,
|
|
|
|
click() {
|
|
|
|
let current_project = Project;
|
|
|
|
project.select();
|
|
|
|
let bbmodel = Codecs.project.compile();
|
|
|
|
current_project.select();
|
|
|
|
Codecs.project.merge(JSON.parse(bbmodel));
|
|
|
|
}
|
|
|
|
})
|
|
|
|
})
|
|
|
|
return projects;
|
|
|
|
}
|
|
|
|
},
|
2021-01-09 20:37:50 +08:00
|
|
|
'import_project',
|
|
|
|
'import_java_block_model',
|
2019-07-18 00:02:07 +08:00
|
|
|
'import_optifine_part',
|
2021-08-21 02:02:28 +08:00
|
|
|
'import_obj',
|
2019-07-18 00:02:07 +08:00
|
|
|
'extrude_texture'
|
|
|
|
]},
|
2019-12-16 03:04:31 +08:00
|
|
|
{name: 'generic.export', id: 'export', icon: 'insert_drive_file', children: [
|
2019-07-18 00:02:07 +08:00
|
|
|
'export_blockmodel',
|
|
|
|
'export_bedrock',
|
|
|
|
'export_entity',
|
|
|
|
'export_class_entity',
|
|
|
|
'export_optifine_full',
|
2019-08-18 00:26:14 +08:00
|
|
|
'export_optifine_part',
|
2021-02-13 21:00:26 +08:00
|
|
|
'export_minecraft_skin',
|
2020-02-08 02:06:24 +08:00
|
|
|
'export_gltf',
|
2021-06-11 22:31:30 +08:00
|
|
|
'export_obj',
|
2019-07-18 00:02:07 +08:00
|
|
|
'upload_sketchfab',
|
2020-11-14 03:43:22 +08:00
|
|
|
'share_model',
|
2019-07-18 00:02:07 +08:00
|
|
|
]},
|
|
|
|
'export_over',
|
|
|
|
'export_asset_archive',
|
|
|
|
'_',
|
2020-09-29 22:32:13 +08:00
|
|
|
{name: 'menu.file.preferences', id: 'preferences', icon: 'tune', children: [
|
|
|
|
'settings_window',
|
|
|
|
'keybindings_window',
|
|
|
|
'theme_window',
|
|
|
|
]},
|
2019-12-16 03:04:31 +08:00
|
|
|
'plugins_window',
|
2020-09-15 20:14:14 +08:00
|
|
|
'edit_session'
|
2019-07-18 00:02:07 +08:00
|
|
|
])
|
|
|
|
new BarMenu('edit', [
|
|
|
|
'undo',
|
|
|
|
'redo',
|
2021-06-02 03:08:41 +08:00
|
|
|
'edit_history',
|
2019-07-18 00:02:07 +08:00
|
|
|
'_',
|
|
|
|
'add_cube',
|
2021-08-03 04:55:30 +08:00
|
|
|
'add_mesh',
|
2019-07-18 00:02:07 +08:00
|
|
|
'add_group',
|
2019-07-19 23:31:22 +08:00
|
|
|
'add_locator',
|
2021-02-01 03:31:45 +08:00
|
|
|
'add_null_object',
|
2021-09-12 21:09:01 +08:00
|
|
|
'add_texture_mesh',
|
2021-08-28 00:19:34 +08:00
|
|
|
'_',
|
|
|
|
'duplicate',
|
2020-12-30 23:37:16 +08:00
|
|
|
'rename',
|
2021-08-28 00:19:34 +08:00
|
|
|
'find_replace',
|
2020-04-26 02:25:07 +08:00
|
|
|
'unlock_everything',
|
2019-07-18 00:02:07 +08:00
|
|
|
'delete',
|
|
|
|
'_',
|
2021-09-25 20:47:41 +08:00
|
|
|
{name: 'data.mesh', id: 'mesh', icon: 'fa-gem', children: [
|
|
|
|
'extrude_mesh_selection',
|
|
|
|
'inset_mesh_selection',
|
|
|
|
'loop_cut',
|
|
|
|
'create_face',
|
|
|
|
'invert_face',
|
|
|
|
'merge_vertices',
|
|
|
|
'merge_vertices_by_distance',
|
|
|
|
'dissolve_edges',
|
|
|
|
'split_mesh',
|
|
|
|
'merge_meshes',
|
|
|
|
]},
|
|
|
|
'_',
|
2019-07-18 00:02:07 +08:00
|
|
|
'select_window',
|
2019-12-16 03:04:31 +08:00
|
|
|
'select_all',
|
2020-03-05 03:56:17 +08:00
|
|
|
'invert_selection'
|
2019-12-16 03:04:31 +08:00
|
|
|
])
|
2019-07-18 00:02:07 +08:00
|
|
|
new BarMenu('transform', [
|
|
|
|
'scale',
|
|
|
|
{name: 'menu.transform.rotate', id: 'rotate', icon: 'rotate_90_degrees_ccw', children: [
|
|
|
|
'rotate_x_cw',
|
|
|
|
'rotate_x_ccw',
|
|
|
|
'rotate_y_cw',
|
|
|
|
'rotate_y_ccw',
|
|
|
|
'rotate_z_cw',
|
|
|
|
'rotate_z_ccw'
|
|
|
|
]},
|
|
|
|
{name: 'menu.transform.flip', id: 'flip', icon: 'flip', children: [
|
|
|
|
'flip_x',
|
|
|
|
'flip_y',
|
|
|
|
'flip_z'
|
|
|
|
]},
|
|
|
|
{name: 'menu.transform.center', id: 'center', icon: 'filter_center_focus', children: [
|
|
|
|
'center_x',
|
|
|
|
'center_y',
|
|
|
|
'center_z',
|
|
|
|
'center_all'
|
|
|
|
]},
|
|
|
|
{name: 'menu.transform.properties', id: 'properties', icon: 'navigate_next', children: [
|
|
|
|
'toggle_visibility',
|
2020-04-26 02:25:07 +08:00
|
|
|
'toggle_locked',
|
2019-07-18 00:02:07 +08:00
|
|
|
'toggle_export',
|
|
|
|
'toggle_autouv',
|
|
|
|
'toggle_shade',
|
2020-12-30 23:37:16 +08:00
|
|
|
'toggle_mirror_uv'
|
2019-07-18 00:02:07 +08:00
|
|
|
]}
|
|
|
|
|
2021-01-27 05:46:17 +08:00
|
|
|
], {
|
|
|
|
condition: {modes: ['edit']}
|
|
|
|
})
|
2019-07-18 00:02:07 +08:00
|
|
|
|
|
|
|
new BarMenu('display', [
|
|
|
|
'copy',
|
|
|
|
'paste',
|
|
|
|
'_',
|
|
|
|
'add_display_preset',
|
2020-04-26 02:25:07 +08:00
|
|
|
'apply_display_preset'
|
2021-01-27 05:46:17 +08:00
|
|
|
], {
|
|
|
|
condition: {modes: ['display']}
|
|
|
|
})
|
2019-07-18 00:02:07 +08:00
|
|
|
|
|
|
|
new BarMenu('filter', [
|
2021-09-10 05:46:03 +08:00
|
|
|
'convert_to_mesh',
|
2019-07-18 00:02:07 +08:00
|
|
|
'remove_blank_faces',
|
|
|
|
])
|
|
|
|
|
|
|
|
new BarMenu('animation', [
|
|
|
|
'copy',
|
|
|
|
'paste',
|
2019-12-16 03:04:31 +08:00
|
|
|
'select_all',
|
2020-01-24 01:53:36 +08:00
|
|
|
'add_keyframe',
|
|
|
|
'add_marker',
|
2019-08-18 00:26:14 +08:00
|
|
|
'reverse_keyframes',
|
2021-05-08 00:31:26 +08:00
|
|
|
{name: 'menu.animation.flip_keyframes', id: 'flip_keyframes', condition: () => Timeline.selected.length, icon: 'flip', children: [
|
2020-09-14 22:26:17 +08:00
|
|
|
'flip_x',
|
|
|
|
'flip_y',
|
|
|
|
'flip_z'
|
|
|
|
]},
|
2021-05-08 00:31:26 +08:00
|
|
|
'flip_animation',
|
2019-07-18 00:02:07 +08:00
|
|
|
'delete',
|
2021-01-23 19:22:05 +08:00
|
|
|
'lock_motion_trail',
|
2019-07-18 00:02:07 +08:00
|
|
|
'_',
|
2019-08-18 00:26:14 +08:00
|
|
|
'select_effect_animator',
|
|
|
|
'_',
|
2019-07-18 00:02:07 +08:00
|
|
|
'load_animation_file',
|
2020-09-28 04:11:37 +08:00
|
|
|
'save_all_animations',
|
2020-12-13 22:12:40 +08:00
|
|
|
'export_animation_file'
|
2021-01-27 05:46:17 +08:00
|
|
|
], {
|
|
|
|
condition: {modes: ['animate']}
|
|
|
|
})
|
2019-07-18 00:02:07 +08:00
|
|
|
|
|
|
|
|
|
|
|
new BarMenu('view', [
|
|
|
|
'fullscreen',
|
|
|
|
'_',
|
2021-05-07 21:57:24 +08:00
|
|
|
'view_mode',
|
2020-03-05 03:56:17 +08:00
|
|
|
'toggle_shading',
|
2020-10-10 21:17:43 +08:00
|
|
|
'toggle_motion_trails',
|
2020-03-05 03:56:17 +08:00
|
|
|
'preview_checkerboard',
|
2019-08-01 06:01:47 +08:00
|
|
|
'painting_grid',
|
2021-01-23 04:31:57 +08:00
|
|
|
'_',
|
2021-06-16 01:05:24 +08:00
|
|
|
'toggle_sidebars',
|
2019-07-18 00:02:07 +08:00
|
|
|
'toggle_quad_view',
|
2021-08-29 15:33:48 +08:00
|
|
|
'hide_everything_except_selection',
|
2020-07-16 15:32:59 +08:00
|
|
|
'focus_on_selection',
|
2019-07-18 00:02:07 +08:00
|
|
|
{name: 'menu.view.screenshot', id: 'screenshot', icon: 'camera_alt', children: [
|
|
|
|
'screenshot_model',
|
|
|
|
'screenshot_app',
|
|
|
|
'record_model_gif',
|
2019-12-16 03:04:31 +08:00
|
|
|
'timelapse',
|
2019-07-18 00:02:07 +08:00
|
|
|
]},
|
|
|
|
])
|
2020-01-24 01:53:36 +08:00
|
|
|
new BarMenu('help', [
|
2020-07-16 15:32:59 +08:00
|
|
|
{name: 'menu.help.search_action', description: BarItems.action_control.description, id: 'search_action', icon: 'search', click: ActionControl.select},
|
|
|
|
'_',
|
2020-01-24 01:53:36 +08:00
|
|
|
{name: 'menu.help.discord', id: 'discord', icon: 'fab.fa-discord', click: () => {
|
|
|
|
Blockbench.openLink('http://discord.blockbench.net');
|
|
|
|
}},
|
2020-03-05 03:56:17 +08:00
|
|
|
{name: 'menu.help.quickstart', id: 'discord', icon: 'fas.fa-directions', click: () => {
|
|
|
|
Blockbench.openLink('https://blockbench.net/quickstart/');
|
|
|
|
}},
|
2021-06-29 16:30:03 +08:00
|
|
|
{name: 'menu.help.wiki', id: 'wiki', icon: 'menu_book', click: () => {
|
|
|
|
Blockbench.openLink('https://blockbench.net/wiki/');
|
|
|
|
}},
|
2020-01-24 01:53:36 +08:00
|
|
|
{name: 'menu.help.report_issue', id: 'report_issue', icon: 'bug_report', click: () => {
|
|
|
|
Blockbench.openLink('https://github.com/JannisX11/blockbench/issues');
|
|
|
|
}},
|
|
|
|
'_',
|
2020-07-16 15:32:59 +08:00
|
|
|
'open_backup_folder',
|
2020-01-24 01:53:36 +08:00
|
|
|
'_',
|
2020-03-05 03:56:17 +08:00
|
|
|
{name: 'menu.help.developer', id: 'developer', icon: 'fas.fa-wrench', children: [
|
|
|
|
'reload_plugins',
|
|
|
|
{name: 'menu.help.plugin_documentation', id: 'plugin_documentation', icon: 'fa-book', click: () => {
|
2021-06-24 22:15:52 +08:00
|
|
|
Blockbench.openLink('https://www.blockbench.net/wiki/api/index');
|
2020-03-05 03:56:17 +08:00
|
|
|
}},
|
2020-10-18 03:54:08 +08:00
|
|
|
'open_dev_tools',
|
2020-03-05 03:56:17 +08:00
|
|
|
{name: 'menu.help.developer.reset_storage', icon: 'fas.fa-hdd', click: () => {
|
|
|
|
if (confirm(tl('menu.help.developer.reset_storage.confirm'))) {
|
|
|
|
localStorage.clear()
|
2020-04-26 02:25:07 +08:00
|
|
|
Blockbench.addFlag('no_localstorage_saving')
|
2020-03-05 03:56:17 +08:00
|
|
|
console.log('Cleared Local Storage')
|
2020-04-26 02:25:07 +08:00
|
|
|
window.location.reload(true)
|
2020-03-05 03:56:17 +08:00
|
|
|
}
|
|
|
|
}},
|
2021-09-30 01:34:03 +08:00
|
|
|
{name: 'menu.help.developer.unlock_projects', id: 'unlock_projects', icon: 'vpn_key', condition: () => ModelProject.all.find(project => project.locked), click() {
|
|
|
|
ModelProject.all.forEach(project => project.locked = false);
|
|
|
|
}},
|
2020-10-18 03:54:08 +08:00
|
|
|
{name: 'menu.help.developer.cache_reload', id: 'cache_reload', icon: 'cached', condition: !isApp, click: () => {
|
2021-04-15 03:19:31 +08:00
|
|
|
if('caches' in window){
|
|
|
|
caches.keys().then((names) => {
|
|
|
|
names.forEach(async (name) => {
|
|
|
|
await caches.delete(name)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
}
|
2020-03-05 03:56:17 +08:00
|
|
|
window.location.reload(true)
|
|
|
|
}},
|
|
|
|
'reload',
|
|
|
|
]},
|
2020-01-24 01:53:36 +08:00
|
|
|
{name: 'menu.help.donate', id: 'donate', icon: 'fas.fa-hand-holding-usd', click: () => {
|
|
|
|
Blockbench.openLink('https://blockbench.net/donate/');
|
|
|
|
}},
|
2021-07-31 05:12:51 +08:00
|
|
|
'about_window'
|
2020-01-24 01:53:36 +08:00
|
|
|
])
|
2019-07-18 00:02:07 +08:00
|
|
|
MenuBar.update()
|
|
|
|
},
|
|
|
|
update() {
|
|
|
|
var bar = $('#menu_bar')
|
|
|
|
bar.children().detach()
|
|
|
|
this.keys = []
|
2020-04-26 02:25:07 +08:00
|
|
|
for (var menu in MenuBar.menus) {
|
|
|
|
if (MenuBar.menus.hasOwnProperty(menu)) {
|
|
|
|
if (MenuBar.menus[menu].conditionMet()) {
|
|
|
|
bar.append(MenuBar.menus[menu].label)
|
2019-07-18 00:02:07 +08:00
|
|
|
this.keys.push(menu)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
addAction(action, path) {
|
|
|
|
if (path) {
|
|
|
|
path = path.split('.')
|
2020-04-26 02:25:07 +08:00
|
|
|
var menu = MenuBar.menus[path.splice(0, 1)[0]]
|
2019-07-18 00:02:07 +08:00
|
|
|
if (menu) {
|
|
|
|
menu.addAction(action, path.join('.'))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
removeAction(path) {
|
|
|
|
if (path) {
|
|
|
|
path = path.split('.')
|
2020-04-26 02:25:07 +08:00
|
|
|
var menu = MenuBar.menus[path.splice(0, 1)[0]]
|
2019-07-18 00:02:07 +08:00
|
|
|
if (menu) {
|
|
|
|
menu.removeAction(path.join('.'))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|