luci-base: ui.js: add LuCI.ui.menu helper class
authorJo-Philipp Wich <jo@mein.io>
Wed, 15 Apr 2020 20:30:00 +0000 (22:30 +0200)
committerJo-Philipp Wich <jo@mein.io>
Thu, 16 Apr 2020 11:30:35 +0000 (13:30 +0200)
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
modules/luci-base/htdocs/luci-static/resources/ui.js

index 235f62a98db0a5aa99989bb7db51a56234892696..21d86fe3dc6a526a2f2b6515d98ea27695b42767 100644 (file)
@@ -2943,6 +2943,84 @@ var UIFileUpload = UIElement.extend(/** @lends LuCI.ui.FileUpload.prototype */ {
        }
 });
 
+/**
+ * Handle menu.
+ *
+ * @constructor menu
+ * @memberof LuCI.ui
+ *
+ * @classdesc
+ *
+ * Handles menus.
+ */
+var UIMenu = baseclass.singleton(/** @lends LuCI.ui.menu.prototype */ {
+       /**
+        * @typedef {Object} MenuNode
+        * @memberof LuCI.ui.menu
+
+        * @property {string} name - The internal name of the node, as used in the URL
+        * @property {number} order - The sort index of the menu node
+        * @property {string} [title] - The title of the menu node, `null` if the node should be hidden
+        * @property {satisified} boolean - Boolean indicating whether the menu enries dependencies are satisfied
+        * @property {readonly} [boolean] - Boolean indicating whether the menu entries underlying ACLs are readonly
+        * @property {LuCI.ui.menu.MenuNode[]} [children] - Array of child menu nodes.
+        */
+
+       /**
+        * Load and cache current menu tree.
+        *
+        * @returns {Promise<LuCI.ui.menu.MenuNode>}
+        * Returns a promise resolving to the root element of the menu tree.
+        */
+       load: function() {
+               if (this.menu == null)
+                       this.menu = session.getLocalData('menu');
+
+               if (!L.isObject(this.menu)) {
+                       this.menu = request.get(L.url('admin/menu')).then(L.bind(function(menu) {
+                               this.menu = menu.json();
+                               session.setLocalData('menu', this.menu);
+
+                               return this.menu;
+                       }, this));
+               }
+
+               return Promise.resolve(this.menu);
+       },
+
+       /**
+        * @param {LuCI.ui.menu.MenuNode} [node]
+        * The menu node to retrieve the children for. Defaults to the menu's
+        * internal root node if omitted.
+        *
+        * @returns {LuCI.ui.menu.MenuNode[]}
+        * Returns an array of child menu nodes.
+        */
+       getChildren: function(node) {
+               var children = [];
+
+               if (node == null)
+                       node = this.menu;
+
+               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));
+               });
+       }
+});
+
 /**
  * @class ui
  * @memberof LuCI
@@ -4297,6 +4375,8 @@ var UI = baseclass.extend(/** @lends LuCI.ui.prototype */ {
                });
        },
 
+       menu: UIMenu,
+
        AbstractElement: UIElement,
 
        /* Widgets */