From 7f227bfc57082cf82995dd4aa38913655b890b9f Mon Sep 17 00:00:00 2001 From: Calum Mackervoy Date: Wed, 5 Feb 2020 12:39:29 +0000 Subject: [PATCH] Refreshing sib-displays in absence of reactive store --- src/page-admin-circles.pug | 5 + src/page-admin-projects.pug | 4 + src/page-circle-left.pug | 5 + src/page-project-left.pug | 5 + src/scripts/index.js | 275 ++++++++++++++++++++++++++---------- 5 files changed, 220 insertions(+), 74 deletions(-) create mode 100644 src/page-circle-left.pug create mode 100644 src/page-project-left.pug diff --git a/src/page-admin-circles.pug b/src/page-admin-circles.pug index 20304b3..110dc4b 100644 --- a/src/page-admin-circles.pug +++ b/src/page-admin-circles.pug @@ -2,11 +2,16 @@ sib-router(default-route='admin-circle-list', hidden) sib-route(name='admin-circle-list') sib-route(name='admin-circle-create') + sib-route(name='circle-left') div.content-box__header.with-description h1.title-left.without-margin Administration + #circle-left(hidden) + include page-circle-left.pug + + #admin-circle-list(hidden) include templates/hd-user-avatar.pug diff --git a/src/page-admin-projects.pug b/src/page-admin-projects.pug index 8e2a915..53ecede 100644 --- a/src/page-admin-projects.pug +++ b/src/page-admin-projects.pug @@ -2,10 +2,14 @@ sib-router(default-route='admin-project-list', hidden) sib-route(name='admin-project-list') sib-route(name='admin-project-create') + sib-route(name='project-left') div.content-box__header.with-description h1.title-left.without-margin Administration + #project-left(hidden) + include page-project-left.pug + #admin-project-list(hidden) include templates/hd-user-avatar.pug diff --git a/src/page-circle-left.pug b/src/page-circle-left.pug new file mode 100644 index 0000000..57a2624 --- /dev/null +++ b/src/page-circle-left.pug @@ -0,0 +1,5 @@ +#circle-left + div.content-box__info(style="padding: 15px") + + p You have successfully left this circle + p This is a private group, to join again, go to the administration panel and ask for an invite diff --git a/src/page-project-left.pug b/src/page-project-left.pug new file mode 100644 index 0000000..b59103f --- /dev/null +++ b/src/page-project-left.pug @@ -0,0 +1,5 @@ +#project-left + div.content-box__info(style="padding: 15px") + + p You have successfully left this project + p This is a private group, to join again, go to the administration panel and ask for an invite diff --git a/src/scripts/index.js b/src/scripts/index.js index ea62622..4b7e6fe 100644 --- a/src/scripts/index.js +++ b/src/scripts/index.js @@ -2,41 +2,50 @@ function recursiveAdaptWidgets(prefix, element, user) { //- 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']); + element.querySelectorAll("[" + prefix + "-user-id]").forEach(el => { + el.setAttribute(el.getAttribute(prefix + "-user-id"), user["@id"]); }); if (element != document) { - //- Allow to bind-user on selected attribute - if (element.getAttribute(prefix + '-user-id')) { - element.setAttribute(element.getAttribute(prefix + '-user-id'), user['@id']); + if (element.getAttribute(prefix + "-user-id")) { + element.setAttribute( + element.getAttribute(prefix + "-user-id"), + user["@id"] + ); } //- Allow to set data-src to a children sib-form - if (element.getAttribute(prefix + '-bind-resources')) { - let form = element.querySelector(element.getAttribute(prefix + '-bind-resources') + " sib-form"); + if (element.getAttribute(prefix + "-bind-resources")) { + let form = element.querySelector( + element.getAttribute(prefix + "-bind-resources") + " sib-form" + ); if (form) { - form.setAttribute('data-src', element.component.resourceId.replace('members/', '')); + form.setAttribute( + "data-src", + element.component.resourceId.replace("members/", "") + ); } } //- Allow to put user on a targetted search field - if (element.getAttribute(prefix + '-bind-user2input')) { - element.querySelector(element.getAttribute(prefix + '-bind-user2input')).value = user['@id']; + if (element.getAttribute(prefix + "-bind-user2input")) { + element.querySelector( + element.getAttribute(prefix + "-bind-user2input") + ).value = user["@id"]; } //- In case your sib-display use a multiple, you have to target sub-sib-display auto-generated - if (element.getAttribute(prefix + '-widgets-multiple') !== null) { - element.querySelectorAll('div > sib-display').forEach((el) => { - el.setAttribute(prefix + '-widgets', ""); + if (element.getAttribute(prefix + "-widgets-multiple") !== null) { + element.querySelectorAll("div > sib-display").forEach(el => { + el.setAttribute(prefix + "-widgets", ""); }); } } //- This function is hooked every time a sib-something with prefix+"-widgets" is populated - element.querySelectorAll('[' + prefix + '-widgets]').forEach((elementChild) => { - elementChild.addEventListener('populate', () => { + element.querySelectorAll("[" + prefix + "-widgets]").forEach(elementChild => { + elementChild.addEventListener("populate", () => { recursiveAdaptWidgets(prefix, elementChild, user); }); }); @@ -44,118 +53,237 @@ function recursiveAdaptWidgets(prefix, element, user) { // auxiliary function closes the user profile menu function closeUserControls() { - let userControls = document.querySelector('#user-controls'); + let userControls = document.querySelector("#user-controls"); if (userControls) userControls.removeAttribute("open"); } function closeLeftMenu() { - let leftMenu = document.querySelector('#main__menu'); + 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')); + 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')); + 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") + ); } -document.addEventListener('DOMContentLoaded', function (event) { - const menuWrappers = Array.from(document.querySelectorAll('.menu-wrapper')); +//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 +} + +//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; + 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/"); + } + + //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'); +} + +document.addEventListener("DOMContentLoaded", function(event) { + const menuWrappers = Array.from(document.querySelectorAll(".menu-wrapper")); //- View change event - window.addEventListener('navigate', (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'); + 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.querySelectorAll('sib-form').forEach(function (el) { - el.addEventListener("save", function (event) { - //clear cache on this resource - //NOTE: this is required because the cache is not refreshed after POSTing changes on the resource - if (el.component.resource != null) el.component.resource.clearCache(); - - // if of the edited resource || id of the container of the created resource - const resourceId = event.detail.resource['@id'] || el.dataset.src; - - //update all displays which use this resource - Array.from(document.querySelectorAll('sib-display')) - .filter(sibDisplay => sibDisplay.component.resourceId == resourceId) // keep only elements with resource == edited resource - .forEach(e => e.dataset.src = e.dataset.src); // and update them - }); + 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('button[role="log in"]').setAttribute('style', 'display:none !important'); - // Set current user id on set-user-id of sib-display - recursiveAdaptWidgets("hd-inherit", document, 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 + 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('button[role="log in"]') + .setAttribute("style", "display:none !important"); + // Set current user id on set-user-id of sib-display + recursiveAdaptWidgets("hd-inherit", document, 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 + } } - } - }).catch(error => console.log(error)); + }) + .catch(error => console.log(error)); // Document -> close menu document.addEventListener("click", event => { - if (!event.target.closest('#user-controls')) { + if (!event.target.closest("#user-controls")) { closeUserControls(); } - if (!event.target.closest('#main__menu') && event.target.id != "toggleMainMenu") { + if ( + !event.target.closest("#main__menu") && + event.target.id != "toggleMainMenu" + ) { closeLeftMenu(); } - if (!event.target.className.includes('jsMobileSidebarOpenButton') && !event.target.className.includes('jsOffsiteToggle')) { + 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')) { + document.querySelector("#toggleMainMenu").addEventListener("click", event => { + let leftMenu = document.querySelector("#main__menu"); + if (leftMenu.hasAttribute("open")) { closeLeftMenu(); } else { - leftMenu.setAttribute('open', ''); + leftMenu.setAttribute("open", ""); } }); - Array.from(document.querySelectorAll('.jsMobileSidebarOpenButton')).forEach(el => { - el.addEventListener('click', event => { - openRightMenu(); - }); - }); + Array.from(document.querySelectorAll(".jsMobileSidebarOpenButton")).forEach( + el => { + el.addEventListener("click", event => { + openRightMenu(); + }); + } + ); - const rightMenus = Array.from(document.querySelectorAll('nav.jsRightMenu')); + 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')) { + btnRightMenu.addEventListener("click", e => { + if (rightMenu.hasAttribute("open")) { closeRightMenu(); } else { openRightMenu(); } - }) + }); }); // listen for keypress - document.onkeydown = (e) => { + document.onkeydown = e => { e = e || window.event; if (e.key === "Escape" || e.key === "Esc") { closeUserControls(); @@ -163,5 +291,4 @@ document.addEventListener('DOMContentLoaded', function (event) { closeRightMenu(); } }; - -}); \ No newline at end of file +});