remove most of jquery from top menu

This commit is contained in:
Simon Vieille 2021-10-29 11:14:27 +02:00
parent cc7c9f6ed5
commit a074d747c1
2 changed files with 142 additions and 105 deletions

View file

@ -1,32 +1,55 @@
var menuCache = null let menuCache = null
var updateTopMenu = function() { const breakpointMobileWidth = 1024
var breakpointMobileWidth = 1024 const usePercentualAppMenuLimit = 0.8
var menu = jQuery('#appmenu') const minAppsDesktop = 8
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
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 return
} }
navigationApps.html('') navigationAppsHtml = ''
apps.each(function(i, app) { for (let app of apps) {
var dataId = app.getAttribute('data-id') const dataId = app.getAttribute('data-id')
if (dataId === null) { if (dataId === null) {
return continue
} }
if (topMenuApps.indexOf(dataId) === -1) { if (topMenuApps.indexOf(dataId) === -1) {
@ -36,25 +59,28 @@ var updateTopMenu = function() {
app.classList.remove('hidden') app.classList.remove('hidden')
app.classList.add('app-external-site') app.classList.add('app-external-site')
appShown.push(app) appShown.push(app)
navigationApps.append(app.outerHTML)
navigationAppsHtml = navigationAppsHtml + app.outerHTML
} }
if (targetBlankApps.indexOf(dataId) !== -1) { 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) { if (isMobile && appCount > minAppsDesktop) {
appCount = minAppsDesktop appCount = minAppsDesktop
@ -63,110 +89,117 @@ var updateTopMenu = function() {
} }
if (appCount === 0) { if (appCount === 0) {
menu.addClass('hidden') menu.classList.add('hidden')
} else {
menu.classList.remove('hidden')
} }
menu.removeClass('hidden') menu.style.opacity = 1
menu.css('opacity', 1)
if (appShown.length - 1 - appCount >= 1) { if (appShown.length - 1 - appCount >= 1) {
appCount-- appCount--
} }
moreApps.find('a').removeClass('active') for (let item of querySelectorAll('a', moreApps)) {
item.classList.remove('active')
}
var k = 0 let k = 0
var notInHeader = 0 let notInHeader = 0
var name
jQuery(appShown).each(function(i, app) { for (let app of appShown) {
app = jQuery(app) const name = app.getAttribute('data-id')
name = app.data('id') const item = querySelector('#apps li[data-id=' + name + '].app-external-site')
if (k < appCount && appCount > 0) { if (k < appCount && appCount > 0) {
app.removeClass('hidden') app.classList.remove('hidden')
lastShownApp = app lastShownApp = app
jQuery('#apps li[data-id=' + name + '].app-external-site').addClass('in-header') item.classList.add('in-header')
} else { } else {
app.addClass('hidden') app.classList.add('hidden')
notInHeader++ 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')) { const a = querySelector('a', app)
lastShownApp.addClass('hidden')
app.removeClass('hidden') if (appCount > 0 && a.classList.contains('active')) {
lastShownApp.classList.add('hidden')
app.classList.remove('hidden')
notInHeader++ notInHeader++
jQuery('#apps li[data-id=' + name + '].app-external-site') item.classList.add('in-header')
.removeClass('in-header')
.addClass('in-header')
} }
} }
k++ k++
}) }
// Hack for https://github.com/nextcloud/server/blob/23b0b63c213f5b31eecae817ffd4a9e26f6624d0/core/src/components/MainMenu.js#L74-L96 // Hack for:
menu.undelegate('li:not(#more-apps) > a', 'click') // - https://github.com/nextcloud/server/blob/master/core/src/components/MainMenu.js#L97-L119
menu.delegate('li:not(#more-apps) > a', 'click', function(e) { // - https://github.com/nextcloud/server/blob/master/core/src/components/MainMenu.js#L97-L119
var a = $(e.target) jQuery(menu).undelegate('li:not(#more-apps) > a', 'click')
jQuery(navigation).undelegate('a', 'click')
if (!a.is('a')) { const confs = [
a = a.closest('a') {
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) { for (let app of querySelectorAll('#apps li.app-external-site')) {
a.find('svg').remove() const appId = app.getAttribute('data-id')
a.find('div').remove()
a.prepend(jQuery('<div/>').addClass(
OCA.Theming && OCA.Theming.inverted
? 'icon-loading-small'
: 'icon-loading-small-dark'
))
window.location.href = a.attr('href') if (app.classList.contains('in-header')) {
} for (let defs of querySelectorAll('svg defs', app)) {
}) defs.remove()
}
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()
} else { } 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; return;
} }
var defs = ` const defs = `
<defs> <defs>
<filter id="invertMenuMore-${appId}"> <filter id="invertMenuMore-${appId}">
<feColorMatrix in="SourceGraphic" type="matrix" values="-1 0 0 0 1 0 -1 0 0 1 0 0 -1 0 1 0 0 0 1 0"></feColorMatrix> <feColorMatrix in="SourceGraphic" type="matrix" values="-1 0 0 0 1 0 -1 0 0 1 0 0 -1 0 1 0 0 0 1 0"></feColorMatrix>
</filter> </filter>
</defs>` </defs>`
svg.prepend(defs) svg.innerHTML = defs + svg.innerHTML
svg.find('image').attr('filter', `url(#invertMenuMore-${appId})`)
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)

View file

@ -94,11 +94,15 @@ if ($_['always-displayed']) {
body.addEventListener('side-menu.ready', () => { body.addEventListener('side-menu.ready', () => {
const sideMenu = querySelector('#side-menu') const sideMenu = querySelector('#side-menu')
const headerMenuOpener = querySelector('#header .side-menu-opener') const headerMenuOpener = querySelector('#header .side-menu-opener')
const sideMenuOpener = querySelector('#side-menu .side-menu-opener') const sideMenuOpener = querySelectorAll('#side-menu .side-menu-opener')
sideMenuFocus = () => { sideMenuFocus = () => {
let a = querySelector('.side-menu-app.active a', sideMenu) let a = querySelector('.side-menu-app.active a', sideMenu)
if (!a) {
return
}
if (a.length === 0) { if (a.length === 0) {
a = querySelector('.side-menu-app:first-child a', sideMenu) a = querySelector('.side-menu-app:first-child a', sideMenu)
} }
@ -108,7 +112,7 @@ if ($_['always-displayed']) {
} }
} }
<?php if ($_['opener-hover'] || $display === 'always-displayed'): ?> <?php if ($_['opener-hover']): ?>
const sideMenuMouseLeave = () => { const sideMenuMouseLeave = () => {
sideMenu.classList.remove('open') sideMenu.classList.remove('open')
sideMenu.removeEventListener('mouseleave', sideMenuMouseLeave) sideMenu.removeEventListener('mouseleave', sideMenuMouseLeave)
@ -142,20 +146,20 @@ if ($_['always-displayed']) {
const a = querySelector('.side-menu-app.active a', sideMenu) const a = querySelector('.side-menu-app.active a', sideMenu)
if (a.length) { if (a !== null) {
a.focus() a.focus()
} }
}) })
<?php if ($display === 'always-displayed'): ?> for (let opener of sideMenuOpener) {
sideMenuOpener.addEventListener('click', () => { opener.addEventListener('click', () => {
sideMenu.classList.toggle('open') <?php if ($display === 'always-displayed'): ?>
sideMenu.classList.toggle('open')
<?php else: ?>
sideMenu.classList.remove('open')
<?php endif; ?>
}) })
<?php else: ?> }
sideMenuOpener.addEventListener('click', () => {
sideMenu.classList.remove('open')
})
<?php endif; ?>
document.addEventListener('keydown', (e) => { document.addEventListener('keydown', (e) => {
var key = e.key || e.keyCode var key = e.key || e.keyCode