From 258f69cc11f8b88ff4a61792675b8f0cd0cb8f24 Mon Sep 17 00:00:00 2001 From: Niko Date: Sat, 26 Feb 2022 02:41:11 +0100 Subject: [PATCH] Created framework for showing menus easily on top of a button click --- web/src/_templates/app/header.php | 4 +- web/src/_templates/app/js.php | 10 +++ web/src/app/css/app.css | 11 ++++ web/src/app/js/app.js | 73 ++++++++++++++++++++-- web/src/app/js/base.js | 9 +++ web/src/app/js/navmenu.js | 5 -- web/src/app/js/templates/overlay/menu.html | 35 +++++++++++ 7 files changed, 136 insertions(+), 11 deletions(-) delete mode 100644 web/src/app/js/navmenu.js create mode 100644 web/src/app/js/templates/overlay/menu.html diff --git a/web/src/_templates/app/header.php b/web/src/_templates/app/header.php index 3845d64..d58f66b 100644 --- a/web/src/_templates/app/header.php +++ b/web/src/_templates/app/header.php @@ -17,7 +17,7 @@ - + @@ -49,7 +49,7 @@
- + diff --git a/web/src/_templates/app/js.php b/web/src/_templates/app/js.php index e73655c..614bca1 100644 --- a/web/src/_templates/app/js.php +++ b/web/src/_templates/app/js.php @@ -23,4 +23,14 @@ var app = { collapse_text_size: 80, }, }; +app.menus = { + navprofile: { + position: 'left', + maxwidth: 35, + items: [ + { text: 'Test', onclick: "alert('test')", fa: 'times' }, + { separator: true }, + ], + }, +}; diff --git a/web/src/app/css/app.css b/web/src/app/css/app.css index 6363b9b..5ef8f2f 100644 --- a/web/src/app/css/app.css +++ b/web/src/app/css/app.css @@ -45,6 +45,17 @@ fieldset label > * { } +#menu-container.left .component.button { + text-align: right !important; +} +#menu-container.right .component.button { + text-align: left !important; +} +#menu-container #menu .button { + padding: 1em; +} + + hr { color: #00000029; } diff --git a/web/src/app/js/app.js b/web/src/app/js/app.js index 504c35b..8dab961 100644 --- a/web/src/app/js/app.js +++ b/web/src/app/js/app.js @@ -7,6 +7,65 @@ app.script = function(name, cback) { loadScript(name, file, cback); } +app.menu = { + show: async function(elem, cfg) { + if (typeof cfg === 'string') + cfg = app.menus[cfg]; + if (cfg === undefined) + return false; + + const items = cfg.items || []; + const position = cfg.position || 'left'; + const maxwidth = em2px(cfg.maxwidth || 35); + + const starty = elem.offsetTop + elem.offsetHeight; + var width = (document.body.clientWidth * 80 / 100); + if (width > maxwidth) width = maxwidth; + + let left + if (position === 'left') + left = Math.floor((elem.offsetLeft + elem.offsetWidth) - width); + else if (position === 'right') + left = Math.floor(elem.offsetLeft); + if (left === undefined) + return false; + + await app.overlay.create('overlay.menu',{ + class: position, + top: starty, + width, + left + }, { removable: true }, function(k,v) { + if (k === 'loop:menu') { + var content = ''; + for (var i = 0; i < items.length; i++) { + var item = items[i]; + item.displayIconRight = 'none'; + item.displayIconLeft = 'none'; + if (item.fa !== undefined) + if (position === 'left') + item.displayIconLeft = 'initial'; + else item.displayIconRight = 'initial'; + item.isItem = item.separator === undefined; + item.isSep = item.separator === true; + item.class = item.class || ''; + content += app.template.fill(item, v); + } + return content; + } + }); + + let elems; + elems = document.querySelectorAll('#menu *[select-isitem="false"]'); + for (var i = 0; i < elems.length; i++) elems[i].remove(); + elems = document.querySelectorAll('#menu *[select-issep="false"]'); + for (var i = 0; i < elems.length; i++) elems[i].remove(); + + return true; + }, +}; + + app.template = { loadMany: async function(names, cback) { var templates = []; @@ -297,9 +356,10 @@ app.emoji = { } app.overlay = { - create: function(template, data, options) { + create: async function(template, data, options, cback) { options = options || {}; - app.template.load(template, function(tpl) { + await app.template.loadMany([template], function(tpl) { + tpl = tpl[0]; const id = 'overlay-'+uuidv4(); const div = document.createElement('div'); data['oid'] = id; @@ -309,12 +369,13 @@ app.overlay = { div.className += ' dark'; if (typeof options.css === 'string') div.className += ` ${options.css}`; - div.innerHTML = app.template.fill(data, tpl); + div.innerHTML = app.template.fill(data, tpl, cback); if (options.removable) div.setAttribute('onclick', `app.overlay.remove("${id}")`); document.body.appendChild(div); calcHeightMobile(); }); + return true; }, remove: function(id) { const elem = document.getElementById(id); @@ -494,7 +555,11 @@ window.onload = function(e) { handle('pages.quiz', /^quiz\/[^\/]+?$/); } - app.template.loadMany(['toast.confirm','toast.info','toast.warn','toast.error']); + app.template.loadMany([ + 'toast.confirm', 'toast.info', + 'toast.warn', 'toast.error', + 'overlay.menu', + ]); if (http.cache.expired('instance_emojis', 30*60)) { http.cache.del('instance_emojis'); http.get('/api/v1/instance/emojis', {}, function(data) { diff --git a/web/src/app/js/base.js b/web/src/app/js/base.js index e43d54f..f6e0cd5 100644 --- a/web/src/app/js/base.js +++ b/web/src/app/js/base.js @@ -167,6 +167,15 @@ function isVisible(element) { ); } +function em2px(em) { + var div = document.createElement('div'); + div.style.width = `${em}em`; + document.body.appendChild(div); + const width = div.offsetWidth; + div.remove(); + return width; +} + function text2html(text) { return text.replaceAll('>','>').replaceAll('<','<') .replaceAll('"', '"').replaceAll('&', '&'); diff --git a/web/src/app/js/navmenu.js b/web/src/app/js/navmenu.js deleted file mode 100644 index 89b2c02..0000000 --- a/web/src/app/js/navmenu.js +++ /dev/null @@ -1,5 +0,0 @@ -app.navmenu = { - show: function() { - console.log('TODO: show menu for profile'); - }, -}; diff --git a/web/src/app/js/templates/overlay/menu.html b/web/src/app/js/templates/overlay/menu.html new file mode 100644 index 0000000..ee9b36f --- /dev/null +++ b/web/src/app/js/templates/overlay/menu.html @@ -0,0 +1,35 @@ +