luci-theme-bootstrap: rework menu rendering
Utilize the LuCI.ui.menu class to load, traverse and cache the menu tree
in the local session store.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
[only render menu when logged in for 19.07]
(backported from commit 1ac8df2614
)
This commit is contained in:
parent
94f504f178
commit
eca8dee353
5 changed files with 123 additions and 147 deletions
|
@ -1787,6 +1787,7 @@ header [data-indicator] {
|
||||||
background-color: #bfbfbf;
|
background-color: #bfbfbf;
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
text-shadow: none;
|
text-shadow: none;
|
||||||
|
margin-left: .4em;
|
||||||
}
|
}
|
||||||
|
|
||||||
header [data-indicator][data-clickable] {
|
header [data-indicator][data-clickable] {
|
||||||
|
@ -1822,10 +1823,6 @@ header [data-indicator][data-style="active"] {
|
||||||
/* LuCI specific items */
|
/* LuCI specific items */
|
||||||
.hidden { display: none }
|
.hidden { display: none }
|
||||||
|
|
||||||
#xhr_poll_status {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
form.inline { display: inline; margin-bottom: 0; }
|
form.inline { display: inline; margin-bottom: 0; }
|
||||||
|
|
||||||
header .pull-right { padding-top: 8px; }
|
header .pull-right { padding-top: 8px; }
|
||||||
|
|
|
@ -0,0 +1,118 @@
|
||||||
|
'use strict';
|
||||||
|
'require baseclass';
|
||||||
|
'require ui';
|
||||||
|
|
||||||
|
return baseclass.extend({
|
||||||
|
__init__: function() {
|
||||||
|
ui.menu.load().then(L.bind(this.render, this));
|
||||||
|
},
|
||||||
|
|
||||||
|
render: function(tree) {
|
||||||
|
var node = tree,
|
||||||
|
url = '';
|
||||||
|
|
||||||
|
this.renderModeMenu(tree);
|
||||||
|
|
||||||
|
if (L.env.dispatchpath.length >= 3) {
|
||||||
|
for (var i = 0; i < 3 && node; i++) {
|
||||||
|
node = node.children[L.env.dispatchpath[i]];
|
||||||
|
url = url + (url ? '/' : '') + L.env.dispatchpath[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node)
|
||||||
|
this.renderTabMenu(node, url);
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener('poll-start', this.handleBodyMargin);
|
||||||
|
document.addEventListener('poll-stop', this.handleBodyMargin);
|
||||||
|
document.addEventListener('uci-new-changes', this.handleBodyMargin);
|
||||||
|
document.addEventListener('uci-clear-changes', this.handleBodyMargin);
|
||||||
|
window.addEventListener('resize', this.handleBodyMargin);
|
||||||
|
|
||||||
|
this.handleBodyMargin();
|
||||||
|
},
|
||||||
|
|
||||||
|
renderTabMenu: function(tree, url, level) {
|
||||||
|
var container = document.querySelector('#tabmenu'),
|
||||||
|
ul = E('ul', { 'class': 'tabs' }),
|
||||||
|
children = ui.menu.getChildren(tree),
|
||||||
|
activeNode = null;
|
||||||
|
|
||||||
|
for (var i = 0; i < children.length; i++) {
|
||||||
|
var isActive = (L.env.dispatchpath[3 + (level || 0)] == children[i].name),
|
||||||
|
activeClass = isActive ? ' active' : '',
|
||||||
|
className = 'tabmenu-item-%s %s'.format(children[i].name, activeClass);
|
||||||
|
|
||||||
|
ul.appendChild(E('li', { 'class': className }, [
|
||||||
|
E('a', { 'href': L.url(url, children[i].name) }, [ _(children[i].title) ] )]));
|
||||||
|
|
||||||
|
if (isActive)
|
||||||
|
activeNode = children[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ul.children.length == 0)
|
||||||
|
return E([]);
|
||||||
|
|
||||||
|
container.appendChild(ul);
|
||||||
|
container.style.display = '';
|
||||||
|
|
||||||
|
if (activeNode)
|
||||||
|
this.renderTabMenu(activeNode, url + '/' + activeNode.name, (level || 0) + 1);
|
||||||
|
|
||||||
|
return ul;
|
||||||
|
},
|
||||||
|
|
||||||
|
renderMainMenu: function(tree, url, level) {
|
||||||
|
var ul = level ? E('ul', { 'class': 'dropdown-menu' }) : document.querySelector('#topmenu'),
|
||||||
|
children = ui.menu.getChildren(tree);
|
||||||
|
|
||||||
|
if (children.length == 0 || level > 1)
|
||||||
|
return E([]);
|
||||||
|
|
||||||
|
for (var i = 0; i < children.length; i++) {
|
||||||
|
var submenu = this.renderMainMenu(children[i], url + '/' + children[i].name, (level || 0) + 1),
|
||||||
|
subclass = (!level && submenu.firstElementChild) ? 'dropdown' : null,
|
||||||
|
linkclass = (!level && submenu.firstElementChild) ? 'menu' : null,
|
||||||
|
linkurl = submenu.firstElementChild ? '#' : L.url(url, children[i].name);
|
||||||
|
|
||||||
|
var li = E('li', { 'class': subclass }, [
|
||||||
|
E('a', { 'class': linkclass, 'href': linkurl }, [ _(children[i].title) ]),
|
||||||
|
submenu
|
||||||
|
]);
|
||||||
|
|
||||||
|
ul.appendChild(li);
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.style.display = '';
|
||||||
|
|
||||||
|
return ul;
|
||||||
|
},
|
||||||
|
|
||||||
|
renderModeMenu: function(tree) {
|
||||||
|
var ul = document.querySelector('#modemenu'),
|
||||||
|
children = ui.menu.getChildren(tree);
|
||||||
|
|
||||||
|
for (var i = 0; i < children.length; i++) {
|
||||||
|
var isActive = (L.env.requestpath.length ? children[i].name == L.env.requestpath[0] : i == 0);
|
||||||
|
|
||||||
|
ul.appendChild(E('li', { 'class': isActive ? 'active' : null }, [
|
||||||
|
E('a', { 'href': L.url(children[i].name) }, [ _(children[i].title) ]),
|
||||||
|
' ',
|
||||||
|
E('span', { 'class': 'divider' }, [ '|' ])
|
||||||
|
]));
|
||||||
|
|
||||||
|
if (isActive)
|
||||||
|
this.renderMainMenu(children[i], children[i].name);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ul.children.length > 1)
|
||||||
|
ul.style.display = '';
|
||||||
|
},
|
||||||
|
|
||||||
|
handleBodyMargin: function(ev) {
|
||||||
|
var body = document.querySelector('body'),
|
||||||
|
head = document.querySelector('header');
|
||||||
|
|
||||||
|
body.style.marginTop = head.offsetHeight + 'px';
|
||||||
|
}
|
||||||
|
});
|
|
@ -12,6 +12,9 @@
|
||||||
<ul class="breadcrumb pull-right" id="modemenu" style="display:none"></ul>
|
<ul class="breadcrumb pull-right" id="modemenu" style="display:none"></ul>
|
||||||
</footer>
|
</footer>
|
||||||
</div>
|
</div>
|
||||||
|
<% if luci.dispatcher.context.authsession then %>
|
||||||
|
<script type="text/javascript">L.require('menu-bootstrap')</script>
|
||||||
|
<% end %>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
||||||
|
|
|
@ -35,9 +35,6 @@
|
||||||
<% end -%>
|
<% end -%>
|
||||||
<script src="<%=url('admin/translations', luci.i18n.context.lang)%><%# ?v=PKG_VERSION %>"></script>
|
<script src="<%=url('admin/translations', luci.i18n.context.lang)%><%# ?v=PKG_VERSION %>"></script>
|
||||||
<script src="<%=resource%>/cbi.js"></script>
|
<script src="<%=resource%>/cbi.js"></script>
|
||||||
<script src="<%=resource%>/xhr.js"></script>
|
|
||||||
|
|
||||||
<% include("themes/bootstrap/json-menu") %>
|
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body class="lang_<%=luci.i18n.context.lang%> <% if node then %><%= striptags( node.title ) %><%- end %>" data-page="<%= pcdata(table.concat(disp.context.requestpath, "-")) %>">
|
<body class="lang_<%=luci.i18n.context.lang%> <% if node then %><%= striptags( node.title ) %><%- end %>" data-page="<%= pcdata(table.concat(disp.context.requestpath, "-")) %>">
|
||||||
|
@ -46,12 +43,7 @@
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<a class="brand" href="#"><%=boardinfo.hostname or "?"%></a>
|
<a class="brand" href="#"><%=boardinfo.hostname or "?"%></a>
|
||||||
<ul class="nav" id="topmenu" style="display:none"></ul>
|
<ul class="nav" id="topmenu" style="display:none"></ul>
|
||||||
<div id="indicators" class="pull-right">
|
<div id="indicators" class="pull-right"></div>
|
||||||
<span id="xhr_poll_status" style="display:none" onclick="XHR.running() ? XHR.halt() : XHR.run()">
|
|
||||||
<span class="label success" id="xhr_poll_status_on"><%:Auto Refresh%> <%:on%></span>
|
|
||||||
<span class="label" id="xhr_poll_status_off" style="display:none"><%:Auto Refresh%> <%:off%></span>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
|
|
@ -1,134 +0,0 @@
|
||||||
<script type="text/javascript">
|
|
||||||
(function() {
|
|
||||||
function get_children(node) {
|
|
||||||
var children = [];
|
|
||||||
|
|
||||||
for (var k in node.children) {
|
|
||||||
if (!node.children.hasOwnProperty(k))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (!node.children[k].satisfied)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (!node.children[k].hasOwnProperty('title'))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
children.push(Object.assign(node.children[k], { name: k }));
|
|
||||||
}
|
|
||||||
|
|
||||||
return children.sort(function(a, b) {
|
|
||||||
return ((a.order || 1000) - (b.order || 1000));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function render_tabmenu(tree, url, level) {
|
|
||||||
var container = document.querySelector('#tabmenu'),
|
|
||||||
ul = E('ul', { 'class': 'tabs' }),
|
|
||||||
children = get_children(tree),
|
|
||||||
activeNode = null;
|
|
||||||
|
|
||||||
for (var i = 0; i < children.length; i++) {
|
|
||||||
var isActive = (L.env.dispatchpath[3 + (level || 0)] == children[i].name),
|
|
||||||
activeClass = isActive ? ' active' : '',
|
|
||||||
className = 'tabmenu-item-%s %s'.format(children[i].name, activeClass);
|
|
||||||
|
|
||||||
ul.appendChild(E('li', { 'class': className }, [
|
|
||||||
E('a', { 'href': L.url(url, children[i].name) }, [ _(children[i].title) ] )]));
|
|
||||||
|
|
||||||
if (isActive)
|
|
||||||
activeNode = children[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ul.children.length == 0)
|
|
||||||
return E([]);
|
|
||||||
|
|
||||||
container.appendChild(ul);
|
|
||||||
container.style.display = '';
|
|
||||||
|
|
||||||
if (activeNode)
|
|
||||||
render_tabmenu(activeNode, url + '/' + activeNode.name, (level || 0) + 1);
|
|
||||||
|
|
||||||
return ul;
|
|
||||||
}
|
|
||||||
|
|
||||||
function render_mainmenu(tree, url, level) {
|
|
||||||
var ul = level ? E('ul', { 'class': 'dropdown-menu' }) : document.querySelector('#topmenu'),
|
|
||||||
children = get_children(tree);
|
|
||||||
|
|
||||||
if (children.length == 0 || level > 1)
|
|
||||||
return E([]);
|
|
||||||
|
|
||||||
for (var i = 0; i < children.length; i++) {
|
|
||||||
var submenu = render_mainmenu(children[i], url + '/' + children[i].name, (level || 0) + 1),
|
|
||||||
subclass = (!level && submenu.firstElementChild) ? 'dropdown' : null,
|
|
||||||
linkclass = (!level && submenu.firstElementChild) ? 'menu' : null,
|
|
||||||
linkurl = submenu.firstElementChild ? '#' : L.url(url, children[i].name);
|
|
||||||
|
|
||||||
var li = E('li', { 'class': subclass }, [
|
|
||||||
E('a', { 'class': linkclass, 'href': linkurl }, [ _(children[i].title) ]),
|
|
||||||
submenu
|
|
||||||
]);
|
|
||||||
|
|
||||||
ul.appendChild(li);
|
|
||||||
}
|
|
||||||
|
|
||||||
ul.style.display = '';
|
|
||||||
|
|
||||||
return ul;
|
|
||||||
}
|
|
||||||
|
|
||||||
function render_modemenu(tree) {
|
|
||||||
var ul = document.querySelector('#modemenu'),
|
|
||||||
children = get_children(tree);
|
|
||||||
|
|
||||||
for (var i = 0; i < children.length; i++) {
|
|
||||||
var isActive = (L.env.requestpath.length ? children[i].name == L.env.requestpath[0] : i == 0);
|
|
||||||
|
|
||||||
ul.appendChild(E('li', { 'class': isActive ? 'active' : null }, [
|
|
||||||
E('a', { 'href': L.url(children[i].name) }, [ _(children[i].title) ]),
|
|
||||||
' ',
|
|
||||||
E('span', { 'class': 'divider' }, [ '|' ])
|
|
||||||
]));
|
|
||||||
|
|
||||||
if (isActive)
|
|
||||||
render_mainmenu(children[i], children[i].name);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ul.children.length > 1)
|
|
||||||
ul.style.display = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
function adjust_body_margin(ev) {
|
|
||||||
var body = document.querySelector('body'),
|
|
||||||
head = document.querySelector('header');
|
|
||||||
|
|
||||||
body.style.marginTop = head.offsetHeight + 'px';
|
|
||||||
}
|
|
||||||
|
|
||||||
document.addEventListener('luci-loaded', function(ev) {
|
|
||||||
var tree = <%= luci.http.write_json(luci.dispatcher.context.authsession and luci.dispatcher.menu_json() or {}) %>,
|
|
||||||
node = tree,
|
|
||||||
url = '';
|
|
||||||
|
|
||||||
render_modemenu(tree);
|
|
||||||
|
|
||||||
if (L.env.dispatchpath.length >= 3) {
|
|
||||||
for (var i = 0; i < 3 && node; i++) {
|
|
||||||
node = node.children[L.env.dispatchpath[i]];
|
|
||||||
url = url + (url ? '/' : '') + L.env.dispatchpath[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (node)
|
|
||||||
render_tabmenu(node, url);
|
|
||||||
}
|
|
||||||
|
|
||||||
document.addEventListener('poll-start', adjust_body_margin);
|
|
||||||
document.addEventListener('poll-stop', adjust_body_margin);
|
|
||||||
document.addEventListener('uci-new-changes', adjust_body_margin);
|
|
||||||
document.addEventListener('uci-clear-changes', adjust_body_margin);
|
|
||||||
window.addEventListener('resize', adjust_body_margin);
|
|
||||||
|
|
||||||
adjust_body_margin(ev);
|
|
||||||
});
|
|
||||||
})();
|
|
||||||
</script>
|
|
Loading…
Reference in a new issue