mirror of
https://github.com/esx-framework/esx_core.git
synced 2026-08-29 17:28:53 +00:00
refactor: esx_menu_Default: better readme + performance + formatting
This commit is contained in:
@@ -1,9 +0,0 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
indent_size = 4
|
||||
indent_style = tab
|
||||
end_of_line = crlf
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
@@ -1,2 +1,18 @@
|
||||
# esx_menu_default
|
||||
ESX Menu Default
|
||||
<h1 align='center'>[ESX] Menu Defualt</a></h1><p align='center'><b><a href='https://discord.esx-framework.org/'>Discord</a> - <a href='https://esx-framework.org/'>Website</a> - <a href='https://docs.esx-framework.org/legacy/installation'>Documentation</a></b></h5>
|
||||
|
||||
A defualt List type menu for ESX.
|
||||
|
||||

|
||||

|
||||
|
||||
## Legal
|
||||
|
||||
esx_menu_defualt - Default Menu!
|
||||
|
||||
Copyright (C) 2015-2022 Jérémie N'gadi
|
||||
|
||||
This program Is free software: you can redistribute it And/Or modify it under the terms Of the GNU General Public License As published by the Free Software Foundation, either version 3 Of the License, Or (at your option) any later version.
|
||||
|
||||
This program Is distributed In the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty Of MERCHANTABILITY Or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License For more details.
|
||||
|
||||
You should have received a copy Of the GNU General Public License along with this program. If Not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
@@ -1,93 +1,117 @@
|
||||
local GUI, MenuType = {}, 'default'
|
||||
local GUI, MenuType, OpenedMenus = {}, 'default', 0
|
||||
GUI.Time = 0
|
||||
|
||||
local function openMenu(namespace, name, data)
|
||||
SendNUIMessage({
|
||||
action = 'openMenu',
|
||||
namespace = namespace,
|
||||
name = name,
|
||||
data = data
|
||||
})
|
||||
OpenedMenus += 1
|
||||
SendNUIMessage({
|
||||
action = 'openMenu',
|
||||
namespace = namespace,
|
||||
name = name,
|
||||
data = data
|
||||
})
|
||||
end
|
||||
|
||||
local function closeMenu(namespace, name)
|
||||
SendNUIMessage({
|
||||
action = 'closeMenu',
|
||||
namespace = namespace,
|
||||
name = name,
|
||||
})
|
||||
OpenedMenus -= 1
|
||||
SendNUIMessage({
|
||||
action = 'closeMenu',
|
||||
namespace = namespace,
|
||||
name = name
|
||||
})
|
||||
end
|
||||
|
||||
ESX.UI.Menu.RegisterType(MenuType, openMenu, closeMenu)
|
||||
|
||||
RegisterNUICallback('menu_submit', function(data, cb)
|
||||
local menu = ESX.UI.Menu.GetOpened(MenuType, data._namespace, data._name)
|
||||
if menu.submit ~= nil then
|
||||
menu.submit(data, menu)
|
||||
end
|
||||
cb('OK')
|
||||
local menu = ESX.UI.Menu.GetOpened(MenuType, data._namespace, data._name)
|
||||
if menu.submit ~= nil then
|
||||
menu.submit(data, menu)
|
||||
end
|
||||
cb('OK')
|
||||
end)
|
||||
|
||||
RegisterNUICallback('menu_cancel', function(data, cb)
|
||||
local menu = ESX.UI.Menu.GetOpened(MenuType, data._namespace, data._name)
|
||||
local menu = ESX.UI.Menu.GetOpened(MenuType, data._namespace, data._name)
|
||||
|
||||
if menu.cancel ~= nil then
|
||||
menu.cancel(data, menu)
|
||||
end
|
||||
cb('OK')
|
||||
if menu.cancel ~= nil then
|
||||
menu.cancel(data, menu)
|
||||
end
|
||||
cb('OK')
|
||||
end)
|
||||
|
||||
RegisterNUICallback('menu_change', function(data, cb)
|
||||
local menu = ESX.UI.Menu.GetOpened(MenuType, data._namespace, data._name)
|
||||
local menu = ESX.UI.Menu.GetOpened(MenuType, data._namespace, data._name)
|
||||
|
||||
for i=1, #data.elements, 1 do
|
||||
menu.setElement(i, 'value', data.elements[i].value)
|
||||
for i = 1, #data.elements, 1 do
|
||||
menu.setElement(i, 'value', data.elements[i].value)
|
||||
|
||||
if data.elements[i].selected then
|
||||
menu.setElement(i, 'selected', true)
|
||||
else
|
||||
menu.setElement(i, 'selected', false)
|
||||
end
|
||||
end
|
||||
if data.elements[i].selected then
|
||||
menu.setElement(i, 'selected', true)
|
||||
else
|
||||
menu.setElement(i, 'selected', false)
|
||||
end
|
||||
end
|
||||
|
||||
if menu.change ~= nil then
|
||||
menu.change(data, menu)
|
||||
end
|
||||
cb('OK')
|
||||
if menu.change ~= nil then
|
||||
menu.change(data, menu)
|
||||
end
|
||||
cb('OK')
|
||||
end)
|
||||
|
||||
CreateThread(function()
|
||||
while true do
|
||||
Wait(15)
|
||||
while true do
|
||||
local Sleep = 500
|
||||
|
||||
if IsControlPressed(0, 18) and IsUsingKeyboard(0) and (GetGameTimer() - GUI.Time) > 150 then
|
||||
SendNUIMessage({action = 'controlPressed', control = 'ENTER'})
|
||||
GUI.Time = GetGameTimer()
|
||||
end
|
||||
if OpenedMenus > 0 then
|
||||
Sleep = 10
|
||||
if IsControlPressed(0, 18) and IsUsingKeyboard(0) and (GetGameTimer() - GUI.Time) > 200 then
|
||||
SendNUIMessage({
|
||||
action = 'controlPressed',
|
||||
control = 'ENTER'
|
||||
})
|
||||
GUI.Time = GetGameTimer()
|
||||
end
|
||||
|
||||
if IsControlPressed(0, 177) and IsUsingKeyboard(0) and (GetGameTimer() - GUI.Time) > 150 then
|
||||
SendNUIMessage({action = 'controlPressed', control = 'BACKSPACE'})
|
||||
GUI.Time = GetGameTimer()
|
||||
end
|
||||
if IsControlPressed(0, 177) and IsUsingKeyboard(0) and (GetGameTimer() - GUI.Time) > 200 then
|
||||
SendNUIMessage({
|
||||
action = 'controlPressed',
|
||||
control = 'BACKSPACE'
|
||||
})
|
||||
GUI.Time = GetGameTimer()
|
||||
end
|
||||
|
||||
if IsControlPressed(0, 27) and IsUsingKeyboard(0) and (GetGameTimer() - GUI.Time) > 200 then
|
||||
SendNUIMessage({action = 'controlPressed', control = 'TOP'})
|
||||
GUI.Time = GetGameTimer()
|
||||
end
|
||||
if IsControlPressed(0, 27) and IsUsingKeyboard(0) and (GetGameTimer() - GUI.Time) > 200 then
|
||||
SendNUIMessage({
|
||||
action = 'controlPressed',
|
||||
control = 'TOP'
|
||||
})
|
||||
GUI.Time = GetGameTimer()
|
||||
end
|
||||
|
||||
if IsControlPressed(0, 173) and IsUsingKeyboard(0) and (GetGameTimer() - GUI.Time) > 200 then
|
||||
SendNUIMessage({action = 'controlPressed', control = 'DOWN'})
|
||||
GUI.Time = GetGameTimer()
|
||||
end
|
||||
if IsControlPressed(0, 173) and IsUsingKeyboard(0) and (GetGameTimer() - GUI.Time) > 200 then
|
||||
SendNUIMessage({
|
||||
action = 'controlPressed',
|
||||
control = 'DOWN'
|
||||
})
|
||||
GUI.Time = GetGameTimer()
|
||||
end
|
||||
|
||||
if IsControlPressed(0, 174) and IsUsingKeyboard(0) and (GetGameTimer() - GUI.Time) > 150 then
|
||||
SendNUIMessage({action = 'controlPressed', control = 'LEFT'})
|
||||
GUI.Time = GetGameTimer()
|
||||
end
|
||||
if IsControlPressed(0, 174) and IsUsingKeyboard(0) and (GetGameTimer() - GUI.Time) > 200 then
|
||||
SendNUIMessage({
|
||||
action = 'controlPressed',
|
||||
control = 'LEFT'
|
||||
})
|
||||
GUI.Time = GetGameTimer()
|
||||
end
|
||||
|
||||
if IsControlPressed(0, 175) and IsUsingKeyboard(0) and (GetGameTimer() - GUI.Time) > 150 then
|
||||
SendNUIMessage({action = 'controlPressed', control = 'RIGHT'})
|
||||
GUI.Time = GetGameTimer()
|
||||
end
|
||||
end
|
||||
if IsControlPressed(0, 175) and IsUsingKeyboard(0) and (GetGameTimer() - GUI.Time) > 200 then
|
||||
SendNUIMessage({
|
||||
action = 'controlPressed',
|
||||
control = 'RIGHT'
|
||||
})
|
||||
GUI.Time = GetGameTimer()
|
||||
end
|
||||
end
|
||||
Wait(Sleep)
|
||||
end
|
||||
end)
|
||||
|
||||
@@ -3,25 +3,13 @@ fx_version 'adamant'
|
||||
game 'gta5'
|
||||
|
||||
description 'ESX Menu Default'
|
||||
|
||||
lua54 'yes'
|
||||
version '1.7.5'
|
||||
|
||||
client_scripts {
|
||||
'@es_extended/imports.lua',
|
||||
'client/main.lua'
|
||||
}
|
||||
client_scripts {'@es_extended/imports.lua', 'client/main.lua'}
|
||||
|
||||
ui_page {
|
||||
'html/ui.html'
|
||||
}
|
||||
ui_page {'html/ui.html'}
|
||||
|
||||
files {
|
||||
'html/ui.html',
|
||||
'html/css/app.css',
|
||||
'html/js/mustache.min.js',
|
||||
'html/js/app.js'
|
||||
}
|
||||
files {'html/ui.html', 'html/css/app.css', 'html/js/mustache.min.js', 'html/js/app.js'}
|
||||
|
||||
dependencies {
|
||||
'es_extended'
|
||||
}
|
||||
dependencies {'es_extended'}
|
||||
|
||||
@@ -1,110 +1,110 @@
|
||||
@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@500;600&display=swap');
|
||||
|
||||
::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
display: none;
|
||||
}
|
||||
|
||||
.menu {
|
||||
font-family: 'Poppins', sans-serif;
|
||||
min-width: 350px;
|
||||
color: #fff;
|
||||
position: absolute;
|
||||
background: rgba(33, 33, 33, 0.0);
|
||||
text-align: center;
|
||||
font-family: 'Poppins', sans-serif;
|
||||
min-width: 350px;
|
||||
color: #fff;
|
||||
position: absolute;
|
||||
background: rgba(33, 33, 33, 0);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.head {
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
padding-bottom: 3px;
|
||||
text-align: center;
|
||||
margin-bottom: 5px;
|
||||
white-space: nowrap;
|
||||
background: rgba(10, 10, 10, 0.9);
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
padding-bottom: 3px;
|
||||
text-align: center;
|
||||
margin-bottom: 5px;
|
||||
white-space: nowrap;
|
||||
background: rgba(10, 10, 10, 0.9);
|
||||
}
|
||||
|
||||
.menu .head {
|
||||
text-align: center;
|
||||
height: 28px;
|
||||
color: #ffffff;
|
||||
font-weight: 700;
|
||||
font-size: 20px;
|
||||
text-align: center;
|
||||
height: 28px;
|
||||
color: #ffffff;
|
||||
font-weight: 700;
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.menu .menu-items {
|
||||
max-height: 450px;
|
||||
overflow-y: auto;
|
||||
font-weight: 550;
|
||||
max-height: 450px;
|
||||
overflow-y: auto;
|
||||
font-weight: 550;
|
||||
}
|
||||
|
||||
.menu-items {
|
||||
margin-bottom: 2px;
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
|
||||
.menu .menu-items .menu-item {
|
||||
display: block;
|
||||
padding: 7px;
|
||||
font-size: 13px;
|
||||
height: 16px;
|
||||
text-indent: 5px;
|
||||
margin-top: 5px;
|
||||
background: rgba(40, 40, 40, 0.8);
|
||||
color: rgb(202, 202, 202);
|
||||
border-radius: 5px;
|
||||
margin-bottom: 6px;
|
||||
display: block;
|
||||
padding: 7px;
|
||||
font-size: 13px;
|
||||
height: 16px;
|
||||
text-indent: 5px;
|
||||
margin-top: 5px;
|
||||
background: rgba(40, 40, 40, 0.8);
|
||||
color: rgb(202, 202, 202);
|
||||
border-radius: 5px;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
.menu .menu-items .menu-item.selected {
|
||||
border: 1px solid rgba(55, 55, 55, 0.9);
|
||||
background: rgba(20, 20, 20, 0.9);
|
||||
color: rgba(243, 243, 243);
|
||||
letter-spacing: 0.2px;
|
||||
font-weight: 500;
|
||||
border: 1px solid rgba(55, 55, 55, 0.9);
|
||||
background: rgba(20, 20, 20, 0.9);
|
||||
color: rgba(243, 243, 243);
|
||||
letter-spacing: 0.2px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.menu.align-left {
|
||||
left: 0;
|
||||
top: 50%;
|
||||
left: 0;
|
||||
top: 50%;
|
||||
}
|
||||
|
||||
.menu.align-top-left {
|
||||
left: 3rem;
|
||||
top: 0;
|
||||
left: 3rem;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.menu.align-top {
|
||||
left: 50%;
|
||||
top: 0;
|
||||
left: 50%;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.menu.align-top-right {
|
||||
right: 3rem;
|
||||
top: 0;
|
||||
right: 3rem;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.menu.align-right {
|
||||
right: 0;
|
||||
top: 50%;
|
||||
right: 0;
|
||||
top: 50%;
|
||||
}
|
||||
|
||||
.menu.align-bottom-right {
|
||||
right: 3rem;
|
||||
bottom: 0;
|
||||
right: 3rem;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.menu.align-bottom {
|
||||
left: 50%;
|
||||
bottom: 0;
|
||||
transform: translate(0, -50%);
|
||||
left: 50%;
|
||||
bottom: 0;
|
||||
transform: translate(0, -50%);
|
||||
}
|
||||
|
||||
.menu.align-bottom-left {
|
||||
left: 3rem;
|
||||
bottom: 0;
|
||||
left: 3rem;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.menu.align-center {
|
||||
left: 50%;
|
||||
top: 35%;
|
||||
transform:translate(-50%, 50%);
|
||||
left: 50%;
|
||||
top: 35%;
|
||||
transform: translate(-50%, 50%);
|
||||
}
|
||||
|
||||
@@ -1,346 +1,378 @@
|
||||
(function(){
|
||||
let MenuTpl =
|
||||
'<div id="menu_{{_namespace}}_{{_name}}" class="menu{{#align}} align-{{align}}{{/align}}">' +
|
||||
'<div class="head"><span>{{{title}}}</span></div>' +
|
||||
'<div class="menu-items">' +
|
||||
'{{#elements}}' +
|
||||
'<div class="menu-item {{#selected}}selected{{/selected}}">' +
|
||||
'{{{label}}}{{#isSlider}} : <{{{sliderLabel}}}>{{/isSlider}}' +
|
||||
'</div>' +
|
||||
'{{/elements}}' +
|
||||
'</div>'+
|
||||
'</div>' +
|
||||
'</div>'
|
||||
;
|
||||
|
||||
window.ESX_MENU = {};
|
||||
ESX_MENU.ResourceName = 'esx_menu_default';
|
||||
ESX_MENU.opened = {};
|
||||
ESX_MENU.focus = [];
|
||||
ESX_MENU.pos = {};
|
||||
|
||||
ESX_MENU.open = function(namespace, name, data) {
|
||||
if (typeof ESX_MENU.opened[namespace] == 'undefined') {
|
||||
ESX_MENU.opened[namespace] = {};
|
||||
}
|
||||
|
||||
if (typeof ESX_MENU.opened[namespace][name] != 'undefined') {
|
||||
ESX_MENU.close(namespace, name);
|
||||
}
|
||||
|
||||
if (typeof ESX_MENU.pos[namespace] == 'undefined') {
|
||||
ESX_MENU.pos[namespace] = {};
|
||||
}
|
||||
|
||||
for (let i=0; i<data.elements.length; i++) {
|
||||
if (typeof data.elements[i].type == 'undefined') {
|
||||
data.elements[i].type = 'default';
|
||||
}
|
||||
}
|
||||
|
||||
data._index = ESX_MENU.focus.length;
|
||||
data._namespace = namespace;
|
||||
data._name = name;
|
||||
|
||||
for (let i=0; i<data.elements.length; i++) {
|
||||
data.elements[i]._namespace = namespace;
|
||||
data.elements[i]._name = name;
|
||||
}
|
||||
|
||||
ESX_MENU.opened[namespace][name] = data;
|
||||
ESX_MENU.pos[namespace][name] = 0;
|
||||
|
||||
for (let i=0; i<data.elements.length; i++) {
|
||||
if (data.elements[i].selected) {
|
||||
ESX_MENU.pos[namespace][name] = i;
|
||||
} else {
|
||||
data.elements[i].selected = false;
|
||||
}
|
||||
}
|
||||
|
||||
ESX_MENU.focus.push({
|
||||
namespace: namespace,
|
||||
name: name
|
||||
});
|
||||
|
||||
ESX_MENU.render();
|
||||
$('#menu_' + namespace + '_' + name).find('.menu-item.selected')[0].scrollIntoView();
|
||||
};
|
||||
|
||||
ESX_MENU.close = function(namespace, name) {
|
||||
delete ESX_MENU.opened[namespace][name];
|
||||
|
||||
for (let i=0; i<ESX_MENU.focus.length; i++) {
|
||||
if (ESX_MENU.focus[i].namespace == namespace && ESX_MENU.focus[i].name == name) {
|
||||
ESX_MENU.focus.splice(i, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ESX_MENU.render();
|
||||
};
|
||||
|
||||
ESX_MENU.render = function() {
|
||||
let menuContainer = document.getElementById('menus');
|
||||
let focused = ESX_MENU.getFocused();
|
||||
menuContainer.innerHTML = '';
|
||||
$(menuContainer).hide();
|
||||
|
||||
for (let namespace in ESX_MENU.opened) {
|
||||
for (let name in ESX_MENU.opened[namespace]) {
|
||||
let menuData = ESX_MENU.opened[namespace][name];
|
||||
let view = JSON.parse(JSON.stringify(menuData));
|
||||
|
||||
for (let i=0; i<menuData.elements.length; i++) {
|
||||
let element = view.elements[i];
|
||||
|
||||
switch (element.type) {
|
||||
case 'default': break;
|
||||
|
||||
case 'slider': {
|
||||
element.isSlider = true;
|
||||
element.sliderLabel = (typeof element.options == 'undefined') ? element.value : element.options[element.value];
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default: break;
|
||||
}
|
||||
|
||||
if (i == ESX_MENU.pos[namespace][name]) {
|
||||
element.selected = true;
|
||||
}
|
||||
}
|
||||
|
||||
let menu = $(Mustache.render(MenuTpl, view))[0];
|
||||
$(menu).hide();
|
||||
menuContainer.appendChild(menu);
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof focused != 'undefined') {
|
||||
$('#menu_' + focused.namespace + '_' + focused.name).show();
|
||||
}
|
||||
|
||||
$(menuContainer).show();
|
||||
|
||||
};
|
||||
|
||||
ESX_MENU.submit = function(namespace, name, data) {
|
||||
$.post('http://' + ESX_MENU.ResourceName + '/menu_submit', JSON.stringify({
|
||||
_namespace: namespace,
|
||||
_name: name,
|
||||
current: data,
|
||||
elements: ESX_MENU.opened[namespace][name].elements
|
||||
}));
|
||||
};
|
||||
|
||||
ESX_MENU.cancel = function(namespace, name) {
|
||||
$.post('http://' + ESX_MENU.ResourceName + '/menu_cancel', JSON.stringify({
|
||||
_namespace: namespace,
|
||||
_name: name
|
||||
}));
|
||||
};
|
||||
|
||||
ESX_MENU.change = function(namespace, name, data) {
|
||||
$.post('http://' + ESX_MENU.ResourceName + '/menu_change', JSON.stringify({
|
||||
_namespace: namespace,
|
||||
_name: name,
|
||||
current: data,
|
||||
elements: ESX_MENU.opened[namespace][name].elements
|
||||
}));
|
||||
};
|
||||
|
||||
ESX_MENU.getFocused = function() {
|
||||
return ESX_MENU.focus[ESX_MENU.focus.length - 1];
|
||||
};
|
||||
|
||||
window.onData = (data) => {
|
||||
switch (data.action) {
|
||||
|
||||
case 'openMenu': {
|
||||
ESX_MENU.open(data.namespace, data.name, data.data);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'closeMenu': {
|
||||
ESX_MENU.close(data.namespace, data.name);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'controlPressed': {
|
||||
switch (data.control) {
|
||||
|
||||
case 'ENTER': {
|
||||
let focused = ESX_MENU.getFocused();
|
||||
|
||||
if (typeof focused != 'undefined') {
|
||||
let menu = ESX_MENU.opened[focused.namespace][focused.name];
|
||||
let pos = ESX_MENU.pos[focused.namespace][focused.name];
|
||||
let elem = menu.elements[pos];
|
||||
|
||||
if (menu.elements.length > 0) {
|
||||
ESX_MENU.submit(focused.namespace, focused.name, elem);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 'BACKSPACE': {
|
||||
let focused = ESX_MENU.getFocused();
|
||||
|
||||
if (typeof focused != 'undefined') {
|
||||
ESX_MENU.cancel(focused.namespace, focused.name);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 'TOP': {
|
||||
let focused = ESX_MENU.getFocused();
|
||||
|
||||
if (typeof focused != 'undefined') {
|
||||
let menu = ESX_MENU.opened[focused.namespace][focused.name];
|
||||
let pos = ESX_MENU.pos[focused.namespace][focused.name];
|
||||
|
||||
if (pos > 0) {
|
||||
ESX_MENU.pos[focused.namespace][focused.name]--;
|
||||
} else {
|
||||
ESX_MENU.pos[focused.namespace][focused.name] = menu.elements.length - 1;
|
||||
}
|
||||
|
||||
let elem = menu.elements[ESX_MENU.pos[focused.namespace][focused.name]];
|
||||
|
||||
for (let i=0; i<menu.elements.length; i++) {
|
||||
if (i == ESX_MENU.pos[focused.namespace][focused.name]) {
|
||||
menu.elements[i].selected = true;
|
||||
} else {
|
||||
menu.elements[i].selected = false;
|
||||
}
|
||||
}
|
||||
|
||||
ESX_MENU.change(focused.namespace, focused.name, elem);
|
||||
ESX_MENU.render();
|
||||
|
||||
$('#menu_' + focused.namespace + '_' + focused.name).find('.menu-item.selected')[0].scrollIntoView();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 'DOWN': {
|
||||
let focused = ESX_MENU.getFocused();
|
||||
|
||||
if (typeof focused != 'undefined') {
|
||||
let menu = ESX_MENU.opened[focused.namespace][focused.name];
|
||||
let pos = ESX_MENU.pos[focused.namespace][focused.name];
|
||||
let length = menu.elements.length;
|
||||
|
||||
if (pos < length - 1) {
|
||||
ESX_MENU.pos[focused.namespace][focused.name]++;
|
||||
} else {
|
||||
ESX_MENU.pos[focused.namespace][focused.name] = 0;
|
||||
}
|
||||
|
||||
let elem = menu.elements[ESX_MENU.pos[focused.namespace][focused.name]];
|
||||
|
||||
for (let i=0; i<menu.elements.length; i++) {
|
||||
if (i == ESX_MENU.pos[focused.namespace][focused.name]) {
|
||||
menu.elements[i].selected = true;
|
||||
} else {
|
||||
menu.elements[i].selected = false;
|
||||
}
|
||||
}
|
||||
|
||||
ESX_MENU.change(focused.namespace, focused.name, elem);
|
||||
ESX_MENU.render();
|
||||
|
||||
$('#menu_' + focused.namespace + '_' + focused.name).find('.menu-item.selected')[0].scrollIntoView();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 'LEFT': {
|
||||
let focused = ESX_MENU.getFocused();
|
||||
|
||||
if (typeof focused != 'undefined') {
|
||||
let menu = ESX_MENU.opened[focused.namespace][focused.name];
|
||||
let pos = ESX_MENU.pos[focused.namespace][focused.name];
|
||||
let elem = menu.elements[pos];
|
||||
|
||||
switch(elem.type) {
|
||||
case 'default': break;
|
||||
|
||||
case 'slider': {
|
||||
let min = (typeof elem.min == 'undefined') ? 0 : elem.min;
|
||||
|
||||
if (elem.value > min) {
|
||||
elem.value--;
|
||||
ESX_MENU.change(focused.namespace, focused.name, elem);
|
||||
}
|
||||
|
||||
ESX_MENU.render();
|
||||
break;
|
||||
}
|
||||
|
||||
default: break;
|
||||
}
|
||||
|
||||
$('#menu_' + focused.namespace + '_' + focused.name).find('.menu-item.selected')[0].scrollIntoView();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 'RIGHT': {
|
||||
let focused = ESX_MENU.getFocused();
|
||||
|
||||
if (typeof focused != 'undefined') {
|
||||
let menu = ESX_MENU.opened[focused.namespace][focused.name];
|
||||
let pos = ESX_MENU.pos[focused.namespace][focused.name];
|
||||
let elem = menu.elements[pos];
|
||||
|
||||
switch(elem.type) {
|
||||
case 'default': break;
|
||||
|
||||
case 'slider': {
|
||||
if (typeof elem.options != 'undefined' && elem.value < elem.options.length - 1) {
|
||||
elem.value++;
|
||||
ESX_MENU.change(focused.namespace, focused.name, elem);
|
||||
}
|
||||
|
||||
if (typeof elem.max != 'undefined' && elem.value < elem.max) {
|
||||
elem.value++;
|
||||
ESX_MENU.change(focused.namespace, focused.name, elem);
|
||||
}
|
||||
|
||||
ESX_MENU.render();
|
||||
break;
|
||||
}
|
||||
|
||||
default: break;
|
||||
}
|
||||
|
||||
$('#menu_' + focused.namespace + '_' + focused.name).find('.menu-item.selected')[0].scrollIntoView();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default: break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
window.onload = function(e){
|
||||
window.addEventListener('message', (event) => {
|
||||
onData(event.data);
|
||||
});
|
||||
};
|
||||
|
||||
})();
|
||||
;(function () {
|
||||
let MenuTpl =
|
||||
'<div id="menu_{{_namespace}}_{{_name}}" class="menu{{#align}} align-{{align}}{{/align}}">' +
|
||||
'<div class="head"><span>{{{title}}}</span></div>' +
|
||||
'<div class="menu-items">' +
|
||||
'{{#elements}}' +
|
||||
'<div class="menu-item {{#selected}}selected{{/selected}}">' +
|
||||
'{{{label}}}{{#isSlider}} : <{{{sliderLabel}}}>{{/isSlider}}' +
|
||||
'</div>' +
|
||||
'{{/elements}}' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'</div>'
|
||||
window.ESX_MENU = {}
|
||||
ESX_MENU.ResourceName = 'esx_menu_default'
|
||||
ESX_MENU.opened = {}
|
||||
ESX_MENU.focus = []
|
||||
ESX_MENU.pos = {}
|
||||
|
||||
ESX_MENU.open = function (namespace, name, data) {
|
||||
if (typeof ESX_MENU.opened[namespace] == 'undefined') {
|
||||
ESX_MENU.opened[namespace] = {}
|
||||
}
|
||||
|
||||
if (typeof ESX_MENU.opened[namespace][name] != 'undefined') {
|
||||
ESX_MENU.close(namespace, name)
|
||||
}
|
||||
|
||||
if (typeof ESX_MENU.pos[namespace] == 'undefined') {
|
||||
ESX_MENU.pos[namespace] = {}
|
||||
}
|
||||
|
||||
for (let i = 0; i < data.elements.length; i++) {
|
||||
if (typeof data.elements[i].type == 'undefined') {
|
||||
data.elements[i].type = 'default'
|
||||
}
|
||||
}
|
||||
|
||||
data._index = ESX_MENU.focus.length
|
||||
data._namespace = namespace
|
||||
data._name = name
|
||||
|
||||
for (let i = 0; i < data.elements.length; i++) {
|
||||
data.elements[i]._namespace = namespace
|
||||
data.elements[i]._name = name
|
||||
}
|
||||
|
||||
ESX_MENU.opened[namespace][name] = data
|
||||
ESX_MENU.pos[namespace][name] = 0
|
||||
|
||||
for (let i = 0; i < data.elements.length; i++) {
|
||||
if (data.elements[i].selected) {
|
||||
ESX_MENU.pos[namespace][name] = i
|
||||
} else {
|
||||
data.elements[i].selected = false
|
||||
}
|
||||
}
|
||||
|
||||
ESX_MENU.focus.push({
|
||||
namespace: namespace,
|
||||
name: name
|
||||
})
|
||||
|
||||
ESX_MENU.render()
|
||||
$('#menu_' + namespace + '_' + name)
|
||||
.find('.menu-item.selected')[0]
|
||||
.scrollIntoView()
|
||||
}
|
||||
|
||||
ESX_MENU.close = function (namespace, name) {
|
||||
delete ESX_MENU.opened[namespace][name]
|
||||
|
||||
for (let i = 0; i < ESX_MENU.focus.length; i++) {
|
||||
if (
|
||||
ESX_MENU.focus[i].namespace == namespace &&
|
||||
ESX_MENU.focus[i].name == name
|
||||
) {
|
||||
ESX_MENU.focus.splice(i, 1)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
ESX_MENU.render()
|
||||
}
|
||||
|
||||
ESX_MENU.render = function () {
|
||||
let menuContainer = document.getElementById('menus')
|
||||
let focused = ESX_MENU.getFocused()
|
||||
menuContainer.innerHTML = ''
|
||||
$(menuContainer).hide()
|
||||
|
||||
for (let namespace in ESX_MENU.opened) {
|
||||
for (let name in ESX_MENU.opened[namespace]) {
|
||||
let menuData = ESX_MENU.opened[namespace][name]
|
||||
let view = JSON.parse(JSON.stringify(menuData))
|
||||
|
||||
for (let i = 0; i < menuData.elements.length; i++) {
|
||||
let element = view.elements[i]
|
||||
|
||||
switch (element.type) {
|
||||
case 'default':
|
||||
break
|
||||
|
||||
case 'slider': {
|
||||
element.isSlider = true
|
||||
element.sliderLabel =
|
||||
typeof element.options == 'undefined'
|
||||
? element.value
|
||||
: element.options[element.value]
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
if (i == ESX_MENU.pos[namespace][name]) {
|
||||
element.selected = true
|
||||
}
|
||||
}
|
||||
|
||||
let menu = $(Mustache.render(MenuTpl, view))[0]
|
||||
$(menu).hide()
|
||||
menuContainer.appendChild(menu)
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof focused != 'undefined') {
|
||||
$('#menu_' + focused.namespace + '_' + focused.name).show()
|
||||
}
|
||||
|
||||
$(menuContainer).show()
|
||||
}
|
||||
|
||||
ESX_MENU.submit = function (namespace, name, data) {
|
||||
$.post(
|
||||
'http://' + ESX_MENU.ResourceName + '/menu_submit',
|
||||
JSON.stringify({
|
||||
_namespace: namespace,
|
||||
_name: name,
|
||||
current: data,
|
||||
elements: ESX_MENU.opened[namespace][name].elements
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
ESX_MENU.cancel = function (namespace, name) {
|
||||
$.post(
|
||||
'http://' + ESX_MENU.ResourceName + '/menu_cancel',
|
||||
JSON.stringify({
|
||||
_namespace: namespace,
|
||||
_name: name
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
ESX_MENU.change = function (namespace, name, data) {
|
||||
$.post(
|
||||
'http://' + ESX_MENU.ResourceName + '/menu_change',
|
||||
JSON.stringify({
|
||||
_namespace: namespace,
|
||||
_name: name,
|
||||
current: data,
|
||||
elements: ESX_MENU.opened[namespace][name].elements
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
ESX_MENU.getFocused = function () {
|
||||
return ESX_MENU.focus[ESX_MENU.focus.length - 1]
|
||||
}
|
||||
|
||||
window.onData = data => {
|
||||
switch (data.action) {
|
||||
case 'openMenu': {
|
||||
ESX_MENU.open(data.namespace, data.name, data.data)
|
||||
break
|
||||
}
|
||||
|
||||
case 'closeMenu': {
|
||||
ESX_MENU.close(data.namespace, data.name)
|
||||
break
|
||||
}
|
||||
|
||||
case 'controlPressed': {
|
||||
switch (data.control) {
|
||||
case 'ENTER': {
|
||||
let focused = ESX_MENU.getFocused()
|
||||
|
||||
if (typeof focused != 'undefined') {
|
||||
let menu = ESX_MENU.opened[focused.namespace][focused.name]
|
||||
let pos = ESX_MENU.pos[focused.namespace][focused.name]
|
||||
let elem = menu.elements[pos]
|
||||
|
||||
if (menu.elements.length > 0) {
|
||||
ESX_MENU.submit(focused.namespace, focused.name, elem)
|
||||
}
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
case 'BACKSPACE': {
|
||||
let focused = ESX_MENU.getFocused()
|
||||
|
||||
if (typeof focused != 'undefined') {
|
||||
ESX_MENU.cancel(focused.namespace, focused.name)
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
case 'TOP': {
|
||||
let focused = ESX_MENU.getFocused()
|
||||
|
||||
if (typeof focused != 'undefined') {
|
||||
let menu = ESX_MENU.opened[focused.namespace][focused.name]
|
||||
let pos = ESX_MENU.pos[focused.namespace][focused.name]
|
||||
|
||||
if (pos > 0) {
|
||||
ESX_MENU.pos[focused.namespace][focused.name]--
|
||||
} else {
|
||||
ESX_MENU.pos[focused.namespace][focused.name] =
|
||||
menu.elements.length - 1
|
||||
}
|
||||
|
||||
let elem =
|
||||
menu.elements[ESX_MENU.pos[focused.namespace][focused.name]]
|
||||
|
||||
for (let i = 0; i < menu.elements.length; i++) {
|
||||
if (i == ESX_MENU.pos[focused.namespace][focused.name]) {
|
||||
menu.elements[i].selected = true
|
||||
} else {
|
||||
menu.elements[i].selected = false
|
||||
}
|
||||
}
|
||||
|
||||
ESX_MENU.change(focused.namespace, focused.name, elem)
|
||||
ESX_MENU.render()
|
||||
|
||||
$('#menu_' + focused.namespace + '_' + focused.name)
|
||||
.find('.menu-item.selected')[0]
|
||||
.scrollIntoView()
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
case 'DOWN': {
|
||||
let focused = ESX_MENU.getFocused()
|
||||
|
||||
if (typeof focused != 'undefined') {
|
||||
let menu = ESX_MENU.opened[focused.namespace][focused.name]
|
||||
let pos = ESX_MENU.pos[focused.namespace][focused.name]
|
||||
let length = menu.elements.length
|
||||
|
||||
if (pos < length - 1) {
|
||||
ESX_MENU.pos[focused.namespace][focused.name]++
|
||||
} else {
|
||||
ESX_MENU.pos[focused.namespace][focused.name] = 0
|
||||
}
|
||||
|
||||
let elem =
|
||||
menu.elements[ESX_MENU.pos[focused.namespace][focused.name]]
|
||||
|
||||
for (let i = 0; i < menu.elements.length; i++) {
|
||||
if (i == ESX_MENU.pos[focused.namespace][focused.name]) {
|
||||
menu.elements[i].selected = true
|
||||
} else {
|
||||
menu.elements[i].selected = false
|
||||
}
|
||||
}
|
||||
|
||||
ESX_MENU.change(focused.namespace, focused.name, elem)
|
||||
ESX_MENU.render()
|
||||
|
||||
$('#menu_' + focused.namespace + '_' + focused.name)
|
||||
.find('.menu-item.selected')[0]
|
||||
.scrollIntoView()
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
case 'LEFT': {
|
||||
let focused = ESX_MENU.getFocused()
|
||||
|
||||
if (typeof focused != 'undefined') {
|
||||
let menu = ESX_MENU.opened[focused.namespace][focused.name]
|
||||
let pos = ESX_MENU.pos[focused.namespace][focused.name]
|
||||
let elem = menu.elements[pos]
|
||||
|
||||
switch (elem.type) {
|
||||
case 'default':
|
||||
break
|
||||
|
||||
case 'slider': {
|
||||
let min = typeof elem.min == 'undefined' ? 0 : elem.min
|
||||
|
||||
if (elem.value > min) {
|
||||
elem.value--
|
||||
ESX_MENU.change(focused.namespace, focused.name, elem)
|
||||
}
|
||||
|
||||
ESX_MENU.render()
|
||||
break
|
||||
}
|
||||
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
$('#menu_' + focused.namespace + '_' + focused.name)
|
||||
.find('.menu-item.selected')[0]
|
||||
.scrollIntoView()
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
case 'RIGHT': {
|
||||
let focused = ESX_MENU.getFocused()
|
||||
|
||||
if (typeof focused != 'undefined') {
|
||||
let menu = ESX_MENU.opened[focused.namespace][focused.name]
|
||||
let pos = ESX_MENU.pos[focused.namespace][focused.name]
|
||||
let elem = menu.elements[pos]
|
||||
|
||||
switch (elem.type) {
|
||||
case 'default':
|
||||
break
|
||||
|
||||
case 'slider': {
|
||||
if (
|
||||
typeof elem.options != 'undefined' &&
|
||||
elem.value < elem.options.length - 1
|
||||
) {
|
||||
elem.value++
|
||||
ESX_MENU.change(focused.namespace, focused.name, elem)
|
||||
}
|
||||
|
||||
if (typeof elem.max != 'undefined' && elem.value < elem.max) {
|
||||
elem.value++
|
||||
ESX_MENU.change(focused.namespace, focused.name, elem)
|
||||
}
|
||||
|
||||
ESX_MENU.render()
|
||||
break
|
||||
}
|
||||
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
$('#menu_' + focused.namespace + '_' + focused.name)
|
||||
.find('.menu-item.selected')[0]
|
||||
.scrollIntoView()
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
window.onload = function (e) {
|
||||
window.addEventListener('message', event => {
|
||||
onData(event.data)
|
||||
})
|
||||
}
|
||||
})()
|
||||
|
||||
@@ -1,18 +1,25 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="stylesheet" href="nui://esx_menu_default/html/css/app.css" />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" />
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=PT+Sans+Narrow&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
</head>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<link rel="stylesheet" href="nui://esx_menu_default/html/css/app.css">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com">
|
||||
<link href="https://fonts.googleapis.com/css2?family=PT+Sans+Narrow&display=swap" rel="stylesheet">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="menus"></div>
|
||||
|
||||
<script src="nui://game/ui/jquery.js" type="text/javascript"></script>
|
||||
<script src="nui://esx_menu_default/html/js/mustache.min.js" type="text/javascript"></script>
|
||||
<script src="nui://esx_menu_default/html/js/app.js" type="text/javascript"></script>
|
||||
</body>
|
||||
<body>
|
||||
<div id="menus"></div>
|
||||
|
||||
<script src="nui://game/ui/jquery.js" type="text/javascript"></script>
|
||||
<script
|
||||
src="nui://esx_menu_default/html/js/mustache.min.js"
|
||||
type="text/javascript"
|
||||
></script>
|
||||
<script
|
||||
src="nui://esx_menu_default/html/js/app.js"
|
||||
type="text/javascript"
|
||||
></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user