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
+});