Skip to content

Commit

Permalink
Notification: render it inline using docTool.getRootSelector()
Browse files Browse the repository at this point in the history
Instead of rendering the notification floating at the top right, we use the
heuristic from `DocumentationTool` class to get the root selector and we prepend
the notification WebComponent there.

Closes #550
  • Loading branch information
humitos committed Feb 20, 2025
1 parent f66a963 commit 398478a
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 4 deletions.
12 changes: 11 additions & 1 deletion src/notification.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ export class NotificationElement extends LitElement {
this.localStorageKey = null;
this.dismissedTimestamp = null;
this.autoDismissed = false;
this.autoDismissEnabled = true;

// Trigger the auto-dismiss timer at startup
this.triggerAutoDismissTimer();
Expand All @@ -66,7 +67,7 @@ export class NotificationElement extends LitElement {
}

triggerAutoDismissTimer() {
if (!document.hidden && !this.autoDismissed) {
if (this.autoDismissEnabled && !document.hidden && !this.autoDismissed) {
clearTimeout(this.timerID);
this.timerID = setTimeout(() => {
this.autoDismissed = true;
Expand Down Expand Up @@ -414,6 +415,15 @@ export class NotificationAddon extends AddonBase {
static addonEnabledPath = "addons.notifications.enabled";
static addonName = "Notification";
static elementClass = NotificationElement;
static elementInjectBehavior = "prepend";

setupInitialBehavior() {
for (const element of this.elements) {
element.autoDismissEnabled = false;
element.clearAutoDismissTimer();
element.className = "raised";
}
}
}

customElements.define(NotificationElement.elementName, NotificationElement);
43 changes: 40 additions & 3 deletions src/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -97,15 +97,52 @@ export class AddonBase {
if (!this.elements.length) {
this.elements = [new this.constructor.elementClass()];

// We cannot use `render(this.elements[0], document.body)` because there is a race conditions between all the addons.
// So, we append the web-component first and then request an update of it.
document.body.append(this.elements[0]);
const injectBehavior = this.constructor.elementInjectBehavior;
const selector = this.getElementInjectSelector();
const elementSelector = document.querySelector(selector);

// Setup the initial behavior only if we are using a custom position for it.
if (selector !== "body") {
this.setupInitialBehavior();
}

if (injectBehavior === "prepend") {
elementSelector.prepend(this.elements[0]);
} else if (injectBehavior === "append") {
elementSelector.append(this.elements[0]);
} else {
// We cannot use `render(this.elements[0], document.body)` because there is a race conditions between all the addons.
// So, we append the web-component first and then request an update of it.
document.body.append(this.elements[0]);
}
}
}

this.loadConfig(config);
}

/**
* Setup the initial behavior of the addon after instatiated.
*
* There are some addons we want to behave differently if we are injecting
* them into a known position in the page, using a custom CSS selector.
*
* This method has to be overriden by the addon.
*/
setupInitialBehavior() {
return null;
}

/**
* Returns the selector where the element has to be injected.
*
* The element will be "appended" or "prepended" based on
* `elementInjectBehavior` static class property.
*/
getElementInjectSelector() {
return docTool.getRootSelector() || "body";
}

loadConfig(config) {
for (const element of this.elements) {
element.loadConfig(config);
Expand Down

0 comments on commit 398478a

Please sign in to comment.