From 125771175a174c9b09143566ed0f02f22331626e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20R=C3=A8gne?= Date: Sun, 8 Nov 2020 14:44:35 +0100 Subject: [PATCH] =?UTF-8?q?feat:=20Afficher=20la=20boite=20de=20dialogue?= =?UTF-8?q?=20quand=20une=20saisie=20est=20demand=C3=A9e.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/core/jsonrpc/input.js | 29 ++++++++++++++++++++ src/core/jsonrpc/kodi.js | 1 + src/photon/style.css | 18 +++++++++++++ src/popup/index.html | 5 +++- src/popup/script.js | 40 +++++++++++++++++++++++++--- src/popup/style.css | 4 +-- test/unit/core/jsonrpc/input.js | 47 +++++++++++++++++++++++++++++++++ 7 files changed, 137 insertions(+), 7 deletions(-) diff --git a/src/core/jsonrpc/input.js b/src/core/jsonrpc/input.js index d8e78450..5215e89f 100644 --- a/src/core/jsonrpc/input.js +++ b/src/core/jsonrpc/input.js @@ -2,6 +2,8 @@ * @module */ +import { NotificationListener } from "./notificationlistener.js"; + /** * Le client JSON-RPC pour contacter l'espace de nom Input de Kodi. * @@ -17,6 +19,8 @@ export const Input = class { */ constructor(kodi) { this.kodi = kodi; + + this.onInputRequested = new NotificationListener(); } /** @@ -130,4 +134,29 @@ export const Input = class { up() { return this.kodi.send("Input.Up"); } + + /** + * Appelle les auditeurs d'une notification liée à l'espace de nom + * Input. + * + * @param {object} notification La notification reçu de Kodi. + * @param {string} notification.method La méthode de la notification. + * @param {object} notification.params Les paramètres de la méthode. + * @param {*} notification.params.data Les données des paramètres. + */ + handleNotification({ method, params: { data } }) { + // Garder seulement les notifications sur les entrées et si des + // auditeurs sont présents. + if (!method.startsWith("Input.") || + 0 === this.onInputRequested.length) { + return; + } + switch (method) { + case "Input.OnInputRequested": + this.onInputRequested.dispatch(data); + break; + default: + // Ignorer les autres notifications. + } + } }; diff --git a/src/core/jsonrpc/kodi.js b/src/core/jsonrpc/kodi.js index 214a5d9e..d4e57cb8 100644 --- a/src/core/jsonrpc/kodi.js +++ b/src/core/jsonrpc/kodi.js @@ -121,6 +121,7 @@ export const Kodi = class { this.jsonrpc = null; }); this.jsonrpc.addEventListener("notification", (event) => { + this.input.handleNotification(event); this.application.handleNotification(event); this.player.handleNotification(event); this.playlist.handleNotification(event); diff --git a/src/photon/style.css b/src/photon/style.css index 694dee9f..cae3cc14 100644 --- a/src/photon/style.css +++ b/src/photon/style.css @@ -14,6 +14,9 @@ p { label { color: #0c0c0d; } +input[type="date"], +input[type="password"], +input[type="number"], input[type="text"] { border: 1px solid rgba(12 12 13 / 20%); border-radius: 2px; @@ -24,18 +27,33 @@ input[type="text"] { transition-duration: 250ms; transition-property: box-shadow; } +input[type="date"]:hover, +input[type="password"]:hover, +input[type="number"]:hover, input[type="text"]:hover { border: 1px solid rgba(12 12 13 / 30%); } +input[type="date"]:invalid, +input[type="password"]:invalid, +input[type="number"]:invalid, input[type="text"]:invalid { border-color: #d70022; box-shadow: 0 0 0 1px #d70022, 0 0 0 4px rgba(251 0 34 / 30%); } +input[type="date"]:focus, +input[type="date"]:focus:hover, +input[type="password"]:focus, +input[type="password"]:focus:hover, +input[type="number"]:focus, +input[type="number"]:focus:hover, input[type="text"]:focus, input[type="text"]:focus:hover { border-color: #0a84ff; box-shadow: 0 0 0 1px #0a84ff, 0 0 0 4px rgba(10 132 255 / 30%); } +input[type="date"]::placeholder, +input[type="password"]::placeholder, +input[type="number"]::placeholder, input[type="text"]::placeholder { color: #737373; } diff --git a/src/popup/index.html b/src/popup/index.html index 5cd289b8..cce64cea 100644 --- a/src/popup/index.html +++ b/src/popup/index.html @@ -233,7 +233,10 @@

diff --git a/src/popup/script.js b/src/popup/script.js index 442fda58..122c3da4 100644 --- a/src/popup/script.js +++ b/src/popup/script.js @@ -341,15 +341,23 @@ const openSendText = function () { } const dialog = document.querySelector("#dialogsendtext"); - dialog.querySelector(`input[name="text"]`).value = ""; - dialog.showModal(); + if (!dialog.open) { + const text = dialog.querySelector(`input[name="text"]`); + text.type = "text"; + text.value = ""; + dialog.showModal(); + } }; const closeDialog = function (event) { // Fermer la boite de dialogue si l'utilisateur clique en dehors de la // boite. - if (event.explicitOriginalTarget.classList.contains("backdrop")) { - event.target.close(); + if ("DIALOG" === event.target.tagName) { + const rect = event.target.getBoundingClientRect(); + if (rect.top > event.clientY || rect.bottom < event.clientY || + rect.left > event.clientX || rect.right < event.clientX) { + event.target.close(); + } } }; @@ -451,6 +459,29 @@ const handleMutedChanged = function (value) { volume.classList.toggle("disabled", value); }; +const handleInputRequested = function ({ type, value }) { + const dialog = document.querySelector("#dialogsendtext"); + if (!dialog.open) { + const text = dialog.querySelector(`input[name="text"]`); + switch (type) { + case "date": + text.type = "date"; + break; + case "password": + case "numericpassword": + text.type = "password"; + break; + case "number": + text.type = "number"; + break; + default: + text.type = "text"; + } + text.value = value; + dialog.showModal(); + } +}; + const handlePositionChanged = function (value) { position = value; if (-1 === value) { @@ -894,6 +925,7 @@ browser.storage.local.get().then((config) => { }); kodi.application.onPropertyChanged.addListener(handlePropertyChanged); +kodi.input.onInputRequested.addListener(handleInputRequested); kodi.player.onPropertyChanged.addListener(handlePropertyChanged); kodi.playlist.onAdd.addListener(async (i) => handleAdd(await complete(i))); kodi.playlist.onClear.addListener(handleClear); diff --git a/src/popup/style.css b/src/popup/style.css index 51131aae..6d88b01e 100644 --- a/src/popup/style.css +++ b/src/popup/style.css @@ -81,10 +81,10 @@ input[type="range"].disabled::-moz-range-progress { #dialogsendtext p:first-child { margin-top: 0; } -#dialogsendtext input[type="text"] { +#dialogsendtext input[name="text"] { width: calc(100% - 16px); } -#dialogsendtext input[type="checkbox"] { +#dialogsendtext input[name="done"] { display: inline-block; } diff --git a/test/unit/core/jsonrpc/input.js b/test/unit/core/jsonrpc/input.js index 12ea4aa2..9298872a 100644 --- a/test/unit/core/jsonrpc/input.js +++ b/test/unit/core/jsonrpc/input.js @@ -177,4 +177,51 @@ describe("core/jsonrpc/input.js", function () { assert.deepStrictEqual(fake.firstCall.args, ["Input.Up"]); }); }); + + describe("handleNotification()", function () { + it("should ignore others namespaces", function (done) { + const input = new Input({ send: Function.prototype }); + input.onInputRequested.addListener(assert.fail); + input.handleNotification({ + method: "Other.OnInputRequested", + params: { data: "foo" }, + }); + done(); + }); + + it("should ignore when no listener", async function () { + const fake = sinon.fake.rejects(new Error("bar")); + + const input = new Input({ send: fake }); + await input.handleNotification({ + method: "Input.OnInputRequested", + params: { data: "foo" }, + }); + + assert.strictEqual(fake.callCount, 0); + }); + + it("should handle 'OnInputRequested'", function (done) { + const input = new Input({ send: Function.prototype }); + input.onInputRequested.addListener((data) => { + assert.deepStrictEqual(data, { foo: "bar" }); + done(); + }); + input.handleNotification({ + method: "Input.OnInputRequested", + params: { data: { foo: "bar" } }, + }); + assert.fail(); + }); + + it("should ignore others notifications", function (done) { + const input = new Input({ send: Function.prototype }); + input.onInputRequested.addListener(assert.fail); + input.handleNotification({ + method: "Input.Other", + params: { data: "foo" }, + }); + done(); + }); + }); });