diff --git a/templates/js/_topMenuApps.js b/templates/js/_topMenuApps.js index 57b7088..589c464 100644 --- a/templates/js/_topMenuApps.js +++ b/templates/js/_topMenuApps.js @@ -1,32 +1,55 @@ -var menuCache = null +let menuCache = null -var updateTopMenu = function() { - var breakpointMobileWidth = 1024 - var menu = jQuery('#appmenu') - var apps = menu.find('li') - var minAppsDesktop = 8 - var usePercentualAppMenuLimit = 0.8 - var isMobile = jQuery(window).width() < breakpointMobileWidth - var lastShownApp = null - var appShown = [] - var moreApps = jQuery('#more-apps') - var navigation = jQuery('#navigation') - var navigationApps = jQuery('#apps ul') - var appCount = null +const breakpointMobileWidth = 1024 +const usePercentualAppMenuLimit = 0.8 +const minAppsDesktop = 8 - var currentMenuCache = menu.html() + menu.next().html() +const handleMenuClick = (e, icon) => { + let element = e.target - if (currentMenuCache === menuCache) { + while (element.tagName !== 'LI') { + element = element.parentNode + } + + const a = querySelector('a', element) + + if (a.getAttribute('target') !== '_blank' && e.which === 1 && !e.ctrlKey && !e.metaKey) { + for (let tag of ['svg', 'div']) { + let el = querySelector(tag, element) + + if (el) { + el.remove() + } + } + + const loader = createElement('div', {'class': icon}) + + a.insertBefore(loader, querySelector('span', a)) + } +} + +const updateTopMenu = function() { + const isMobile = window.innerWidth < breakpointMobileWidth + const menu = querySelector('#appmenu') + const moreApps = querySelector('#more-apps') + const navigation = querySelector('#navigation') + const navigationApps = querySelector('#apps ul') + + let apps = querySelectorAll('li', menu) + let lastShownApp = null + let appShown = [] + + if ((menu.innerHTML + menu.nextSibling.innerHTML) === menuCache) { return } - navigationApps.html('') + navigationAppsHtml = '' - apps.each(function(i, app) { - var dataId = app.getAttribute('data-id') + for (let app of apps) { + const dataId = app.getAttribute('data-id') if (dataId === null) { - return + continue } if (topMenuApps.indexOf(dataId) === -1) { @@ -36,25 +59,28 @@ var updateTopMenu = function() { app.classList.remove('hidden') app.classList.add('app-external-site') appShown.push(app) - navigationApps.append(app.outerHTML) + + navigationAppsHtml = navigationAppsHtml + app.outerHTML } if (targetBlankApps.indexOf(dataId) !== -1) { - jQuery(app).children('a').attr('target', '_blank'); + querySelector('a', app).setAttribute('target', '_blank') } - }) - - var rightHeaderWidth = jQuery('.header-right').outerWidth() - var headerWidth = jQuery('header').outerWidth() - var availableWidth = headerWidth - jQuery('#nextcloud').outerWidth() - - jQuery('#header .side-menu-opener').outerWidth() - - (rightHeaderWidth > 230 ? rightHeaderWidth : 230) - - if (!isMobile) { - availableWidth = availableWidth * usePercentualAppMenuLimit } - appCount = Math.floor(availableWidth / jQuery('#appmenu li').width()) + navigationApps.innerHTML = navigationAppsHtml + + const rightHeaderWidth = querySelector('.header-right').offsetWidth + const headerWidth = querySelector('header').offsetWidth + + let availableWidth = headerWidth + + availableWidth -= nextcloud.offsetWidth + availableWidth -= querySelector('#header .side-menu-opener').offsetWidth + availableWidth -= rightHeaderWidth > 230 ? rightHeaderWidth : 230 + availableWidth *= isMobile ? usePercentualAppMenuLimit : 1 + + let appCount = Math.floor(availableWidth / querySelector('#appmenu li:not(.hidden)').offsetWidth) if (isMobile && appCount > minAppsDesktop) { appCount = minAppsDesktop @@ -63,110 +89,117 @@ var updateTopMenu = function() { } if (appCount === 0) { - menu.addClass('hidden') + menu.classList.add('hidden') + } else { + menu.classList.remove('hidden') } - menu.removeClass('hidden') - menu.css('opacity', 1) + menu.style.opacity = 1 if (appShown.length - 1 - appCount >= 1) { appCount-- } - moreApps.find('a').removeClass('active') + for (let item of querySelectorAll('a', moreApps)) { + item.classList.remove('active') + } - var k = 0 - var notInHeader = 0 - var name + let k = 0 + let notInHeader = 0 - jQuery(appShown).each(function(i, app) { - app = jQuery(app) - name = app.data('id') + for (let app of appShown) { + const name = app.getAttribute('data-id') + const item = querySelector('#apps li[data-id=' + name + '].app-external-site') if (k < appCount && appCount > 0) { - app.removeClass('hidden') + app.classList.remove('hidden') lastShownApp = app - jQuery('#apps li[data-id=' + name + '].app-external-site').addClass('in-header') + item.classList.add('in-header') } else { - app.addClass('hidden') + app.classList.add('hidden') notInHeader++ - jQuery('#apps li[data-id=' + name + '].app-external-site').removeClass('in-header') + item.classList.remove('in-header') - if (appCount > 0 && app.children('a').hasClass('active')) { - lastShownApp.addClass('hidden') - app.removeClass('hidden') + const a = querySelector('a', app) + + if (appCount > 0 && a.classList.contains('active')) { + lastShownApp.classList.add('hidden') + app.classList.remove('hidden') notInHeader++ - jQuery('#apps li[data-id=' + name + '].app-external-site') - .removeClass('in-header') - .addClass('in-header') + item.classList.add('in-header') } } k++ - }) + } - // Hack for https://github.com/nextcloud/server/blob/23b0b63c213f5b31eecae817ffd4a9e26f6624d0/core/src/components/MainMenu.js#L74-L96 - menu.undelegate('li:not(#more-apps) > a', 'click') - menu.delegate('li:not(#more-apps) > a', 'click', function(e) { - var a = $(e.target) + // Hack for: + // - https://github.com/nextcloud/server/blob/master/core/src/components/MainMenu.js#L97-L119 + // - https://github.com/nextcloud/server/blob/master/core/src/components/MainMenu.js#L97-L119 + jQuery(menu).undelegate('li:not(#more-apps) > a', 'click') + jQuery(navigation).undelegate('a', 'click') - if (!a.is('a')) { - a = a.closest('a') + const confs = [ + { + items: querySelectorAll('#navigation li'), + icon: 'icon-loading-small' + }, + { + items: querySelectorAll('li:not(#more-apps)', menu), + icon: OCA.Theming && OCA.Theming.inverted ? 'icon-loading-small' : 'icon-loading-small-dark' + }, + ] + + for (let conf of confs) { + for (let item of conf.items) { + item.addEventListener('click', (e) => { + handleMenuClick(e, conf.icon) + }) } + } - if (a.attr('target') !== '_blank' && e.which === 1 && !e.ctrlKey && !e.metaKey && a.parent('#more-apps').length === 0) { - a.find('svg').remove() - a.find('div').remove() - a.prepend(jQuery('
').addClass( - OCA.Theming && OCA.Theming.inverted - ? 'icon-loading-small' - : 'icon-loading-small-dark' - )) + for (let app of querySelectorAll('#apps li.app-external-site')) { + const appId = app.getAttribute('data-id') - window.location.href = a.attr('href') - } - }) - - jQuery('#apps li.app-external-site').each(function(i, app) { - app = jQuery(app) - var appId = app.attr('data-id') - - if (app.hasClass('in-header')) { - app.find('svg').find('defs').remove() + if (app.classList.contains('in-header')) { + for (let defs of querySelectorAll('svg defs', app)) { + defs.remove() + } } else { - var svg = app.find('svg'); + const svg = querySelector('svg', app) - if (svg.find('defs').length > 0) { + if (querySelectorAll('svg defs', app).length > 0) { return; } - var defs = ` + const defs = ` ` - svg.prepend(defs) - svg.find('image').attr('filter', `url(#invertMenuMore-${appId})`) + svg.innerHTML = defs + svg.innerHTML - var html = svg.get(0).innerHTML.replace(/fecolormatrix/g, 'feColorMatrix'); + for (let image of querySelectorAll('image', svg)) { + image.setAttribute('filter', `url(#invertMenuMore-${appId})`) + } - svg.html(html) + svg.innerHTML = svg.innerHTML.replace(/fecolormatrix/g, 'feColorMatrix') } - }) - - if (notInHeader === 0) { - moreApps.hide() - navigation.hide() - } else { - moreApps.show() } - menuCache = menu.html() + menu.next().html() + if (notInHeader === 0) { + moreApps.style.display = 'none' + navigation.style.display = 'none' + } else { + moreApps.style.display = 'flex' + } + + menuCache = menu.innerHTML + menu.nextSibling.innerHTML } -setInterval(updateTopMenu, 50) +setInterval(updateTopMenu, 1000) diff --git a/templates/js/script.php b/templates/js/script.php index e32af22..8f22477 100644 --- a/templates/js/script.php +++ b/templates/js/script.php @@ -94,11 +94,15 @@ if ($_['always-displayed']) { body.addEventListener('side-menu.ready', () => { const sideMenu = querySelector('#side-menu') const headerMenuOpener = querySelector('#header .side-menu-opener') - const sideMenuOpener = querySelector('#side-menu .side-menu-opener') + const sideMenuOpener = querySelectorAll('#side-menu .side-menu-opener') sideMenuFocus = () => { let a = querySelector('.side-menu-app.active a', sideMenu) + if (!a) { + return + } + if (a.length === 0) { a = querySelector('.side-menu-app:first-child a', sideMenu) } @@ -108,7 +112,7 @@ if ($_['always-displayed']) { } } - + const sideMenuMouseLeave = () => { sideMenu.classList.remove('open') sideMenu.removeEventListener('mouseleave', sideMenuMouseLeave) @@ -142,20 +146,20 @@ if ($_['always-displayed']) { const a = querySelector('.side-menu-app.active a', sideMenu) - if (a.length) { + if (a !== null) { a.focus() } }) - - sideMenuOpener.addEventListener('click', () => { - sideMenu.classList.toggle('open') + for (let opener of sideMenuOpener) { + opener.addEventListener('click', () => { + + sideMenu.classList.toggle('open') + + sideMenu.classList.remove('open') + }) - - sideMenuOpener.addEventListener('click', () => { - sideMenu.classList.remove('open') - }) - + } document.addEventListener('keydown', (e) => { var key = e.key || e.keyCode