luci-theme-bootstrap: rework menu rendering
authorJo-Philipp Wich <jo@mein.io>
Wed, 15 Apr 2020 20:46:25 +0000 (22:46 +0200)
committerJo-Philipp Wich <jo@mein.io>
Thu, 16 Apr 2020 11:30:35 +0000 (13:30 +0200)
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>
themes/luci-theme-bootstrap/htdocs/luci-static/bootstrap/cascade.css
themes/luci-theme-bootstrap/htdocs/luci-static/resources/menu-bootstrap.js [new file with mode: 0644]
themes/luci-theme-bootstrap/luasrc/view/themes/bootstrap/footer.htm
themes/luci-theme-bootstrap/luasrc/view/themes/bootstrap/header.htm
themes/luci-theme-bootstrap/luasrc/view/themes/bootstrap/json-menu.htm [deleted file]

index 4387e9588902f7a53caf54db5b9965cba6d91e39..63eb51cceb5311b035d0529e380c71add46e53e7 100644 (file)
@@ -1787,6 +1787,7 @@ header [data-indicator] {
        background-color: #bfbfbf;
        border-radius: 3px;
        text-shadow: none;
+       margin-left: .4em;
 }
 
 header [data-indicator][data-clickable] {
@@ -1822,10 +1823,6 @@ header [data-indicator][data-style="active"] {
 /* LuCI specific items */
 .hidden { display: none }
 
-#xhr_poll_status {
-         cursor: pointer;
-}
-
 form.inline { display: inline; margin-bottom: 0; }
 
 header .pull-right { padding-top: 8px; }
diff --git a/themes/luci-theme-bootstrap/htdocs/luci-static/resources/menu-bootstrap.js b/themes/luci-theme-bootstrap/htdocs/luci-static/resources/menu-bootstrap.js
new file mode 100644 (file)
index 0000000..5400276
--- /dev/null
@@ -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';
+       }
+});
index ec6895f06d098edff3141bbcf17b9c62ecc9e5d1..d0c395bf314e8bbe40de58e6e754ce04f3f2df83 100644 (file)
@@ -12,6 +12,7 @@
     <ul class="breadcrumb pull-right" id="modemenu" style="display:none"></ul>
    </footer>
   </div>
+  <script type="text/javascript">L.require('menu-bootstrap')</script>
  </body>
 </html>
 
index 39415154aa8b378d2989d78a0f562c8bdd08b51d..89aa338152fa35ddadbb93b73d77c1596dab6880 100644 (file)
@@ -35,9 +35,6 @@
                <% end -%>
                <script src="<%=url('admin/translations', luci.i18n.context.lang)%><%# ?v=PKG_VERSION %>"></script>
                <script src="<%=resource%>/cbi.js"></script>
-               <script src="<%=resource%>/xhr.js"></script>
-
-               <% include("themes/bootstrap/json-menu") %>
        </head>
 
        <body class="lang_<%=luci.i18n.context.lang%> <% if node then %><%= striptags( node.title ) %><%- end %>" data-page="<%= pcdata(table.concat(disp.context.requestpath, "-")) %>">
                                <div class="container">
                                        <a class="brand" href="#"><%=boardinfo.hostname or "?"%></a>
                                        <ul class="nav" id="topmenu" style="display:none"></ul>
-                                       <div id="indicators" class="pull-right">
-                                               <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 id="indicators" class="pull-right"></div>
                                </div>
                        </div>
                </header>
diff --git a/themes/luci-theme-bootstrap/luasrc/view/themes/bootstrap/json-menu.htm b/themes/luci-theme-bootstrap/luasrc/view/themes/bootstrap/json-menu.htm
deleted file mode 100644 (file)
index ea11cf2..0000000
+++ /dev/null
@@ -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.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>