diff --git a/asset/webcomponent/app.js b/asset/webcomponent/app.js
index a6c7bb7..3515fc5 100644
--- a/asset/webcomponent/app.js
+++ b/asset/webcomponent/app.js
@@ -11,4 +11,7 @@ window.customElements.define("ui-textarea", UiTextarea);
import { UiSelect } from "./module/ui-select.js";
window.customElements.define("ui-select", UiSelect);
+import { UiNotification } from "./module/ui-notification.js";
+window.customElements.define("ui-notification", UiNotification);
+
import './module/input.js';
\ No newline at end of file
diff --git a/asset/webcomponent/module/ui-notification.js b/asset/webcomponent/module/ui-notification.js
new file mode 100644
index 0000000..34a1806
--- /dev/null
+++ b/asset/webcomponent/module/ui-notification.js
@@ -0,0 +1,102 @@
+import { Webcomponent } from "./webcomponent.js";
+
+class UiNotification extends Webcomponent {
+
+ #intervalId;
+
+ constructor() {
+ super({
+ template: {
+ fetch:false
+ }
+ });
+ }
+
+ connectedCallback() {
+ if ( this.activate() ) {
+ this.start_pooling();
+ }
+ }
+
+ activate() {
+ if (window.Notification) {
+ if ( (Notification.permission !== "denied") && (Notification.permission !== 'granted') ) {
+ this.style.visibility = "visible";
+ this.style.cursor = "pointer";
+
+ this.addEventListener('click', e => {
+ Notification.requestPermission().then((permission) => {
+ this.style.visibility = "hidden";
+ this.start_pooling();
+ });
+ });
+ }
+ else {
+ return Notification.permission === "granted";
+ }
+ }
+
+ return false;
+ }
+
+ start_pooling() {
+ this.intervalId = setInterval(this.pool.bind(this), this.interval);
+ }
+
+ stop_pooling() {
+ clearInterval(this.intervalId);
+ }
+
+ pool() {
+ if (Notification.permission === "granted") {
+ fetch(this.url_fetch + "?ts=" + this.timestamp)
+ .then(response => response.json())
+ .then(data =>{
+ if (data.notification) {
+ var notification = new Notification(data.title, {
+ icon: this.url_icon,
+ body: data.body,
+ });
+
+ notification.onclick = function () {
+ let win = window.open(data.url, data.title);
+
+ setTimeout(e => win.focus(), 600);
+ };
+
+ this.timestamp = data.timestamp;
+ }
+ });
+ }
+ }
+
+ get timestamp() {
+ return this.dataset.timestamp;
+ }
+
+ set timestamp(value) {
+ return this.dataset.timestamp = value;
+ }
+
+ get url_fetch() {
+ return this.dataset.url;
+ }
+
+ get url_icon() {
+ return this.dataset.icon ? this.dataset.icon : null;
+ }
+
+ get interval() {
+ return this.dataset.interval ? this.dataset.interval : Math.floor(Math.random() * (45000 - 15000) + 15000);
+ }
+
+ get intervalId() {
+ return this.#intervalId;
+ }
+
+ set intervalId(value) {
+ return this.#intervalId = value;
+ }
+}
+
+export { UiNotification }
\ No newline at end of file
diff --git a/view/webcomponent/ui-notification.phtml b/view/webcomponent/ui-notification.phtml
index 2f4bd55..c12f34b 100644
--- a/view/webcomponent/ui-notification.phtml
+++ b/view/webcomponent/ui-notification.phtml
@@ -14,9 +14,6 @@
-
- {# Todo ! #}
-