Skip to content

Commit b75b4e1

Browse files
refactor: remove jQuery dependency and replace with vanilla JavaScript
1 parent 1ab9fe4 commit b75b4e1

File tree

5 files changed

+151
-80
lines changed

5 files changed

+151
-80
lines changed

CHANGELOG.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/)
66
and this project adheres to [Semantic Versioning](https://semver.org/).
77

8+
## unreleased
9+
10+
### Changed
11+
12+
- refactor: remove jQuery dependency and replace with vanilla JavaScript
13+
814
## [3.1.6](https://github.com/jopyth/MMM-Remote-Control/compare/v3.1.5...v3.1.6) - 2025-04-13
915

1016
### Changed
@@ -102,7 +108,7 @@ There shouldn't be any breaking changes in this release. But since there are a s
102108

103109
### Changed
104110

105-
- Use npm package for jquery, showdown and swagger-ui (and switch to current versions)
111+
- Use npm package for jQuery, showdown and swagger-ui (and switch to current versions)
106112
- Update dependencies
107113
- Handle some linter issues
108114
- Drop Google fonts for API page

package-lock.json

Lines changed: 0 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@
3232
},
3333
"dependencies": {
3434
"body-parser": "^2.2.0",
35-
"jquery": "^3.7.1",
3635
"showdown": "^2.1.0",
3736
"simple-git": "^3.27.0",
3837
"swagger-ui": "^5.21.0",

remote.html

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -509,10 +509,6 @@
509509
<script type="text/javascript" src="config/config.js"></script>
510510
<script type="text/javascript" src="socket.io/socket.io.js"></script>
511511
<script type="text/javascript" src="js/socketclient.js"></script>
512-
<script
513-
type="text/javascript"
514-
src="modules/MMM-Remote-Control/node_modules/jquery/dist/jquery.slim.min.js"
515-
></script>
516512
<script
517513
type="text/javascript"
518514
src="modules/MMM-Remote-Control/node_modules/showdown/dist/showdown.min.js"

remote.js

Lines changed: 144 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* global $ MMSocket showdown */
1+
/* global MMSocket showdown */
22

33
// main javascript file for the remote control page
44

@@ -221,12 +221,15 @@ const Remote = {
221221
},
222222

223223
closePopup () {
224-
$("#popup-container").hide();
225-
$("#popup-contents").empty();
224+
const popupContainer = document.getElementById("popup-container");
225+
const popupContents = document.getElementById("popup-contents");
226+
if (popupContainer) popupContainer.style.display = "none";
227+
if (popupContents) popupContents.innerHTML = "";
226228
},
227229

228230
showPopup () {
229-
$("#popup-container").show();
231+
const popupContainer = document.getElementById("popup-container");
232+
if (popupContainer) popupContainer.style.display = "block";
230233
},
231234

232235
getPopupContent (clear) {
@@ -236,7 +239,7 @@ const Remote = {
236239
if (clear) {
237240
this.closePopup();
238241
}
239-
return $("#popup-contents")[0];
242+
return document.getElementById("popup-contents");
240243
},
241244

242245
loadOtherElements () {
@@ -370,8 +373,9 @@ const Remote = {
370373

371374
// Simple status update
372375
if (status === "success" && !message && !customContent) {
373-
$("#success-popup").show();
374-
this.autoHideTimer = setTimeout(() => { $("#success-popup").hide(); }, this.autoHideDelay);
376+
const successPopup = document.getElementById("success-popup");
377+
successPopup.style.display = "block";
378+
this.autoHideTimer = setTimeout(() => { successPopup.style.display = "none"; }, this.autoHideDelay);
375379
return;
376380
}
377381

@@ -462,9 +466,19 @@ const Remote = {
462466
install (url, index) {
463467
const self = this;
464468

465-
const $downloadButton = $("#download-button");
466-
$downloadButton.children(":first").removeClass("fa-download").addClass("fa-spinner fa-pulse");
467-
$downloadButton.children(":last").html(` ${self.translate("DOWNLOADING")}`);
469+
const downloadButton = document.getElementById("download-button");
470+
const icon = downloadButton.querySelector("span:first-child");
471+
const text = downloadButton.querySelector("span:last-child");
472+
473+
if (icon) {
474+
icon.classList.remove("fa-download");
475+
icon.classList.add("fa-spinner", "fa-pulse");
476+
}
477+
478+
if (text) {
479+
text.innerHTML = ` ${self.translate("DOWNLOADING")}`;
480+
}
481+
468482
this.sendSocketNotification("REMOTE_ACTION", {action: "INSTALL", url, index});
469483
},
470484

@@ -1267,19 +1281,30 @@ const Remote = {
12671281
console.log("Loading classes...");
12681282
this.loadList("classes", "classes", (parent, classes) => {
12691283
for (const i in classes) {
1270-
$node = $("<div>").attr("id", "classes-before-result").attr("hidden", "true");
1271-
$("#classes-results").append($node);
1272-
const content = {id: i,
1284+
const node = document.createElement("div");
1285+
node.id = "classes-before-result";
1286+
node.hidden = true;
1287+
document.getElementById("classes-results").appendChild(node);
1288+
1289+
const content = {
1290+
id: i,
12731291
text: i,
12741292
icon: "dot-circle-o",
12751293
type: "item",
1276-
action: "MANAGE_CLASSES", content: {
1294+
action: "MANAGE_CLASSES",
1295+
content: {
12771296
payload: {
12781297
classes: i
12791298
}
1280-
}};
1281-
if ($(`#${content.id}-button`)) { $(`#${content.id}-button`).remove(); }
1282-
self.createMenuElement(content, "classes", $("#classes-before-result"));
1299+
}
1300+
};
1301+
1302+
const existingButton = document.getElementById(`${content.id}-button`);
1303+
if (existingButton) {
1304+
existingButton.remove();
1305+
}
1306+
1307+
self.createMenuElement(content, "classes", node);
12831308
}
12841309
});
12851310
},
@@ -1540,76 +1565,127 @@ const Remote = {
15401565
this.createDynamicMenu();
15411566
},
15421567

1543-
createMenuElement (content, menu, $insertAfter) {
1568+
createMenuElement (content, menu, insertAfter) {
15441569
if (!content) { return; }
1545-
$item = $("<div>").attr("id", `${content.id}-button`).addClass(`menu-element button ${menu}-menu`);
1546-
const $mcmIcon = $("<span>").addClass(`fa fa-fw fa-${content.icon}`).attr("aria-hidden", "true");
1547-
const $mcmText = $("<span>").addClass("text").text(content.text);
1548-
$item.append($mcmIcon).append($mcmText);
1549-
if (content.icon) { $item.append($mcmIcon); }
1570+
const item = document.createElement("div");
1571+
item.id = `${content.id}-button`;
1572+
item.className = `menu-element button ${menu}-menu`;
1573+
1574+
if (content.icon) {
1575+
const mcmIcon = document.createElement("span");
1576+
mcmIcon.className = `fa fa-fw fa-${content.icon}`;
1577+
mcmIcon.setAttribute("aria-hidden", "true");
1578+
item.appendChild(mcmIcon);
1579+
}
1580+
1581+
if (content.text) {
1582+
const mcmText = document.createElement("span");
1583+
mcmText.className = "text";
1584+
mcmText.textContent = content.text;
1585+
item.appendChild(mcmText);
1586+
}
1587+
15501588
if (content.type === "menu") {
1551-
if (content.text) { $item.append($mcmText); }
1552-
const $mcmArrow = $("<span>").addClass("fa fa-fw fa-angle-right").attr("aria-hidden", "true");
1553-
$item.append($mcmArrow);
1554-
$item.attr("data-parent", menu).attr("data-type", "menu");
1555-
$("#back-button").addClass(`${content.id}-menu`);
1556-
$("#below-fold").addClass(`${content.id}-menu`);
1557-
$item.click(() => { window.location.hash = `${content.id}-menu`; });
1558-
} else if (content.type === "slider") {
1559-
if (content.text) { $item.append($mcmText.attr("style", "flex: 0 1 auto")); }
1560-
const $contain = $("<div>").attr("style", "flex: 1");
1561-
const $slide = $("<input>").attr("id", `${content.id}-slider`).addClass("slider");
1562-
$slide.attr({
1563-
"type": "range",
1564-
"min": content.min || 0,
1565-
"max": content.max || 100,
1566-
"step": content.step || 10,
1567-
"value": content.defaultValue || 50
1589+
const mcmArrow = document.createElement("span");
1590+
mcmArrow.className = "fa fa-fw fa-angle-right";
1591+
mcmArrow.setAttribute("aria-hidden", "true");
1592+
item.appendChild(mcmArrow);
1593+
item.setAttribute("data-parent", menu);
1594+
item.setAttribute("data-type", "menu");
1595+
document.getElementById("back-button").classList.add(`${content.id}-menu`);
1596+
document.getElementById("below-fold").classList.add(`${content.id}-menu`);
1597+
item.addEventListener("click", () => {
1598+
window.location.hash = `${content.id}-menu`;
15681599
});
1569-
$slide.change(() => {
1570-
this.sendSocketNotification("REMOTE_ACTION", {action: content.action.toUpperCase(), ...content.content, payload: {...content.content == undefined ? {} : typeof content.content.payload === "string" ? {string: content.content.payload} : content.content.payload, value: document.getElementById(`${content.id}-slider`).value}, value: document.getElementById(`${content.id}-slider`).value});
1600+
} else if (content.type === "slider") {
1601+
const contain = document.createElement("div");
1602+
contain.style.flex = "1";
1603+
1604+
const slide = document.createElement("input");
1605+
slide.id = `${content.id}-slider`;
1606+
slide.className = "slider";
1607+
slide.type = "range";
1608+
slide.min = content.min || 0;
1609+
slide.max = content.max || 100;
1610+
slide.step = content.step || 10;
1611+
slide.value = content.defaultValue || 50;
1612+
1613+
slide.addEventListener("change", () => {
1614+
this.sendSocketNotification("REMOTE_ACTION", {
1615+
action: content.action.toUpperCase(),
1616+
...content.content,
1617+
payload: {
1618+
...content.content === undefined ? {} : typeof content.content.payload === "string" ? {string: content.content.payload} : content.content.payload,
1619+
value: slide.value
1620+
},
1621+
value: slide.value
1622+
});
15711623
});
1572-
$contain.append($slide);
1573-
$item.append($contain);
1624+
1625+
contain.appendChild(slide);
1626+
item.appendChild(contain);
15741627
} else if (content.type === "input") {
1575-
$item = $("<input>").addClass(`menu-element ${menu}-menu medium`).attr({
1576-
"id": `${content.id}-input`,
1577-
"type": "text",
1578-
"placeholder": content.text || ""
1579-
});
1580-
$item.focusout(() => {
1581-
this.sendSocketNotification("REMOTE_ACTION", {action: content.action.toUpperCase(), ...content.content, payload: {...content.content == undefined ? {} : typeof content.content.payload === "string" ? {string: content.content.payload} : content.content.payload, value: document.getElementById(`${content.id}-input`).value}, value: document.getElementById(`${content.id}-input`).value});
1628+
const input = document.createElement("input");
1629+
input.id = `${content.id}-input`;
1630+
input.className = `menu-element ${menu}-menu medium`;
1631+
input.type = "text";
1632+
input.placeholder = content.text || "";
1633+
1634+
input.addEventListener("focusout", () => {
1635+
this.sendSocketNotification("REMOTE_ACTION", {
1636+
action: content.action.toUpperCase(),
1637+
...content.content,
1638+
payload: {
1639+
...content.content === undefined ? {} : typeof content.content.payload === "string" ? {string: content.content.payload} : content.content.payload,
1640+
value: input.value
1641+
},
1642+
value: input.value
1643+
});
15821644
});
1645+
1646+
return input;
15831647
} else if (content.action && content.content) {
1584-
if (content.text) { $item.append($mcmText); }
1585-
$item.attr("data-type", "item");
1586-
// let payload = content.content.payload || {};
1587-
$item.click(() => {
1588-
this.sendSocketNotification("REMOTE_ACTION", {action: content.action.toUpperCase(), payload: {}, ...content.content});
1648+
item.setAttribute("data-type", "item");
1649+
item.addEventListener("click", () => {
1650+
this.sendSocketNotification("REMOTE_ACTION", {
1651+
action: content.action.toUpperCase(),
1652+
payload: {},
1653+
...content.content
1654+
});
15891655
});
15901656
}
1657+
15911658
if (!window.location.hash && menu !== "main" ||
15921659
window.location.hash && window.location.hash.substring(1) !== `${menu}-menu`) {
1593-
$item.addClass("hidden");
1660+
item.classList.add("hidden");
15941661
}
1595-
$item.insertAfter($insertAfter);
1662+
1663+
insertAfter.parentNode.insertBefore(item, insertAfter.nextSibling);
1664+
15961665
if ("items" in content) {
15971666
content.items.forEach((i) => {
1598-
this.createMenuElement(i, content.id, $item);
1667+
this.createMenuElement(i, content.id, item);
15991668
});
16001669
}
1601-
return $item;
1670+
1671+
return item;
16021672
},
16031673

16041674
createDynamicMenu (content) {
1605-
if (content && $(`#${content.id}-button`)) {
1606-
$(`#${content.id}-button`).remove();
1607-
$("div").remove(`.${content.id}-menu`);
1608-
if (window.location.hash === `${content.id}-menu`) {
1675+
if (content) {
1676+
const buttonElement = document.getElementById(`${content.id}-button`);
1677+
if (buttonElement) {
1678+
buttonElement.remove();
1679+
}
1680+
1681+
const menuElements = document.querySelectorAll(`.${content.id}-menu`);
1682+
menuElements.forEach((menuElement) => menuElement.remove());
1683+
1684+
if (window.location.hash === `#${content.id}-menu`) {
16091685
window.location.hash = "main-menu";
16101686
}
16111687
}
1612-
this.createMenuElement(content, "main", $("#alert-button"));
1688+
this.createMenuElement(content, "main", document.getElementById("alert-button"));
16131689
}
16141690
};
16151691

@@ -1652,8 +1728,9 @@ const buttons = {
16521728
window.location.hash = "settings-menu";
16531729
return;
16541730
}
1655-
if ($(window.location.hash.replace("-menu", "-button")).data("parent")) {
1656-
window.location.hash = `${$(window.location.hash.replace("-menu", "-button")).data("parent")}-menu`;
1731+
const currentButton = document.querySelector(window.location.hash.replace("-menu", "-button"));
1732+
if (currentButton && currentButton.dataset.parent) {
1733+
window.location.hash = `${currentButton.dataset.parent}-menu`;
16571734
return;
16581735
}
16591736
window.location.hash = "main-menu";

0 commit comments

Comments
 (0)