function applyAdapt(prefix, sibDisplay, user) { //- Allow to bind-user on selected attribute if (sibDisplay.getAttribute(prefix + "-user-id")) { sibDisplay.setAttribute( sibDisplay.getAttribute(prefix + "-user-id"), user["@id"] ); } //- Allow to set data-src to a children sib-form if (sibDisplay.getAttribute(prefix + "-bind-resources")) { let form = sibDisplay.querySelector( sibDisplay.getAttribute(prefix + "-bind-resources") + " sib-form" ); if (form) { form.setAttribute( "data-src", sibDisplay.component.resourceId.replace("members/", "") ); } } //- Allow to put user on a targetted search field if (sibDisplay.getAttribute(prefix + "-bind-user2input")) { sibDisplay.querySelector( sibDisplay.getAttribute(prefix + "-bind-user2input") ).value = user["@id"]; } } function recursiveAdaptWidgets(prefix, element, user) { element.addEventListener("populate", () => { //- This function is a workaround for the currently unworking populate //- Feel free to see examples on page-circles- element.querySelectorAll("[" + prefix + "-user-id]").forEach(el => { el.setAttribute(el.getAttribute(prefix + "-user-id"), user["@id"]); }); applyAdapt(prefix, element, user); document.querySelectorAll('sib-display, sib-form').forEach(sibDisplay => { applyAdapt(prefix, sibDisplay, user); }); }); } // auxiliary function closes the user profile menu function closeUserControls() { let userControls = document.querySelector("#user-controls"); if (userControls) userControls.removeAttribute("open"); } function closeLeftMenu() { let leftMenu = document.querySelector("#main__menu"); if (leftMenu) leftMenu.removeAttribute("open"); } function closeRightMenu() { let rightMenu = document.querySelectorAll(".jsRightMenu"); if (Array.from(rightMenu).filter(el => el.hasAttribute("open")).length > 0) { Array.from(document.querySelectorAll(".views-container")).forEach(vC => vC.classList.toggle("sidebar-is-closed") ); Array.from(rightMenu).forEach(el => el.removeAttribute("open")); } } function openRightMenu() { let rightMenu = document.querySelectorAll(".jsRightMenu"); Array.from(rightMenu).forEach(el => el.setAttribute("open", "")); Array.from(document.querySelectorAll(".views-container")).forEach(vC => vC.classList.toggle("sidebar-is-closed") ); } //auxiliary function clears cache & refreshes sib-displays for a given resource ID function refreshSibDisplays(resourceId, clearCache = true) { let cacheCleared = false; Array.from(document.querySelectorAll("sib-display")) .filter(sibDisplay => sibDisplay.component.resourceId == resourceId) // keep only elements with resource == edited resource .forEach(e => { //clear cache if we were unable to before if ((clearCache && !cacheCleared) && e.component.resource != null) { e.component.resource.clearCache(); cacheCleared = true; } e.dataset.src = e.dataset.src; }); // and update them } async function updateSources(resource) { let res = resource.split('/'); res.splice(3, 0, 'sources'); let cacheCleared = false; if (event.target.component.resource != null) { event.target.component.resource.clearCache(); cacheCleared = true; } refreshSibDisplays(res.join('/'),cacheCleared); } //auxiliary function updates displays using a given resource //NOTE: this is a temporary workaround and should be replaced by a reactive storage //https://git.happy-dev.fr/startinblox/framework/sib-core/issues/524 async function refreshResource(event) { // if of the edited resource || id of the container of the created resource const resourceId = event.detail.resource["@id"] || event.target.dataset.src; updateSources(resourceId, event); let resource = document .querySelector('[data-src="' + resourceId + '"]') .component.resource.getResourceData(); //special case: refresh circles/X/ from circle-members/Y/ let partnerId = null; if (resourceId.includes("circle-members")) { partnerId = resource["http://happy-dev.fr/owl/#circle"]["@id"]; } else if (resourceId.includes("project-members")) { partnerId = resource["http://happy-dev.fr/owl/#project"]["@id"]; } //refresh all resources using the partner ID if (partnerId != null) { refreshSibDisplays(partnerId); refreshSibDisplays(partnerId + "members/"); } //special cases updating users/X/circles for the left-side-menu (leaving or joining circle) let user = await document.querySelector('sib-auth').getUser(); if(resourceId.includes('circle') && user != null) { let userId = user['@id']; refreshSibDisplays(userId + "circles/"); refreshSibDisplays(resourceId.split('/').slice(0,4).join('/')+'/joinable/'); } //clear cache on this resource //NOTE: this is required because the cache is not refreshed after POSTing changes on the resource let cacheCleared = false; if (event.target.component.resource != null) { event.target.component.resource.clearCache(); cacheCleared = true; } //update all displays which use this resource refreshSibDisplays(resourceId, cacheCleared); } //auxiliary function performs a redirect //NOTE: currently a sib-display is required to dispatch the requestNavigation event function performRedirect(route) { document.dispatchEvent( new CustomEvent("requestNavigation", { bubbles: true, detail: { route: route } }) ); } //auxiliary function redirects after leaving a project/circle //NOTE: this is a temporary workaround until the following issues are resolved: //https://git.happy-dev.fr/startinblox/framework/sib-core/issues/476 //https://git.happy-dev.fr/startinblox/framework/sib-core/issues/546 async function checkForPostLeaveRedirect(event) { //a redirect will only be required if I left in the information page of the resource if(!window.location.href.includes('-information')) return; //first need to get a sib-display with this resource id (to have access to the target Proxy, containing model fields) const resourceId = event.detail.resource['@id'] || event.target.dataset.src; let target = document.querySelector('[data-src="' + resourceId + '"]'); let resource = target.component.resource.getResourceData(); //no redirect is required for public circles let targetCircleId = resource["http://happy-dev.fr/owl/#circle"]["@id"]; if(targetCircleId != undefined) { let targetCircle = document.querySelector('[data-src="' + targetCircleId + '"]'); let targetCircleResource = targetCircle.component.resource.getResourceData(); if(targetCircleResource['http://happy-dev.fr/owl/#status'] == 'Public') return; } //a redirect will only be required if I've deleted myself let targetUser = resource['http://happy-dev.fr/owl/#user']; //compare with current user let user = await document.querySelector('sib-auth').getUser(); if(targetUser['@id'] != user['@id'] && targetUser['@id'] != undefined) return; //perform the redirect if(resourceId.includes('circle')) performRedirect('circle-left'); else if(resourceId.includes('project')) performRedirect('project-left'); } //- Update badges from notifications list async function updateBadges(element) { const unreadNotifications = new Map(); const notifications = element.component.resource; if (!notifications) return; // Generate unread map for (let notification of notifications['ldp:contains']) { if (await notification['unread']) { const object = await notification['object']; unreadNotifications.set(object['@id'], (unreadNotifications.get(object['@id']) || 0) + 1); } } // update badges unreadNotifications.forEach((notifNumber, objectId) => { const badge = document.querySelector(`sib-fix-badge[data-src="${objectId}"]`); if (badge) { badge.innerText = notifNumber || ''; badge.style.display = notifNumber ? 'block' : 'none'; } }) } document.addEventListener("DOMContentLoaded", function(event) { const menuWrappers = Array.from(document.querySelectorAll(".menu-wrapper")); //- View change event window.addEventListener("navigate", event => { closeLeftMenu(); closeUserControls(); }); //- Toggle sub-menus menuWrappers.forEach(menuWrapper => { const menu = menuWrapper.querySelector(".menu"); menu.addEventListener("click", e => { menuWrapper.classList.toggle("is-closed"); }); }); //- Watch every sib-forms & update data-src of linked sib-display document.querySelector("body").addEventListener("save", event => { refreshResource(event); }); document.querySelector("body").addEventListener("resourceDeleted", event => { //I might need to be redirected from this page checkForPostLeaveRedirect(event).then(refreshResource(event)); }); document .querySelector("sib-auth") .getUser() .then(user => { if (user !== null) { document .querySelectorAll(".notLoggedIn") .forEach(el => (el.style.visibility = "visible")); // Hide login button if already logged document .querySelector('.loggedIn') .setAttribute("style", "display:none !important"); document.querySelectorAll('sib-display, sib-form').forEach(element => { // Set current user id on set-user-id of sib-display recursiveAdaptWidgets("hd-inherit", element, user); }); for (leaveBtn of document.querySelectorAll( "admin-circle-leave > sib-ac-checker:not([hidden])" )) { leaveBtn.parentNode.parentNode.parentNode.nextElementSibling.setAttribute( "style", "display:none !important" ); // Hide Join button } } else { document.querySelector('sib-auth').login(); } }) .catch(error => console.log(error)); // Document -> close menu document.addEventListener("click", event => { if (!event.target.closest("#user-controls")) { closeUserControls(); } if ( !event.target.closest("#main__menu") && event.target.id != "toggleMainMenu" ) { closeLeftMenu(); } if ( !event.target.className.includes("jsMobileSidebarOpenButton") && !event.target.className.includes("jsOffsiteToggle") ) { closeRightMenu(); } }); document.querySelector("#toggleMainMenu").addEventListener("click", event => { let leftMenu = document.querySelector("#main__menu"); if (leftMenu.hasAttribute("open")) { closeLeftMenu(); } else { leftMenu.setAttribute("open", ""); } }); Array.from(document.querySelectorAll(".jsMobileSidebarOpenButton")).forEach( el => { el.addEventListener("click", event => { openRightMenu(); }); } ); const rightMenus = Array.from(document.querySelectorAll("nav.jsRightMenu")); rightMenus.forEach(rightMenu => { const btnRightMenu = rightMenu.querySelector("li.jsOffsiteToggle"); btnRightMenu.addEventListener("click", e => { if (rightMenu.hasAttribute("open")) { closeRightMenu(); } else { openRightMenu(); } }); }); // listen for keypress document.onkeydown = e => { e = e || window.event; if (e.key === "Escape" || e.key === "Esc") { closeUserControls(); closeLeftMenu(); closeRightMenu(); } }; //- Fix badges performances // on load time const checkNotificationMenuExist = setInterval(function () { // wait for notification menu to exist const notifsMenu = document.getElementById('notifications-list'); if (notifsMenu) { clearInterval(checkNotificationMenuExist); notifsMenu.addEventListener('populate', (event) => { const checkExist = setInterval(function () { // wait for left menus to exist const subMenus = document.querySelectorAll('.sub-menu > sib-display > div'); if (subMenus.length >= 2) { updateBadges(event.target); clearInterval(checkExist); } }, 500); }, { once: true }); } }, 500); // on refresh notification list window.addEventListener('notificationsRefresh', () => { document.getElementById('notifications-list').addEventListener('populate', (event) => { updateBadges(event.target); }, { once: true }); }); // on read notification window.addEventListener('read', (event) => { if (event.detail && event.detail.resource && event.detail.resource['@id']) { const badge = document.querySelector(`sib-fix-badge[data-src="${event.detail.resource['@id']}"]`); if (badge) badge.style.display = "none"; } }); });