diff --git a/client/js/autocompletion.js b/client/js/autocompletion.js index fc3e8f48..df778041 100644 --- a/client/js/autocompletion.js +++ b/client/js/autocompletion.js @@ -14,8 +14,8 @@ let textcomplete; module.exports = { enable: enableAutocomplete, disable: () => { - input.unbind("input.tabcomplete"); - Mousetrap(input.get(0)).unbind("tab", "keydown"); + input.off("input.tabcomplete"); + Mousetrap(input.get(0)).off("tab", "keydown"); if (textcomplete) { textcomplete.destroy(); diff --git a/client/js/join-channel.js b/client/js/join-channel.js index ebeea808..da1c2d93 100644 --- a/client/js/join-channel.js +++ b/client/js/join-channel.js @@ -20,8 +20,8 @@ function toggleButton(network) { // Toggle content of tooltip const tooltip = network.find(".add-channel-tooltip"); const altLabel = tooltip.data("alt-label"); - tooltip.data("alt-label", tooltip.attr("aria-label")); - tooltip.attr("aria-label", altLabel); + tooltip.data("alt-label", tooltip.prop("aria-label")); + tooltip.prop("aria-label", altLabel); } function closeForm(network) { @@ -44,7 +44,7 @@ function openForm(network) { } // Focus the "Channel" field even if the form was already open - form.find(".input[name='channel']").focus(); + form.find(".input[name='channel']").trigger("focus"); } sidebar.on("click", ".add-channel", function(e) { @@ -69,7 +69,7 @@ sidebar.on("submit", ".join-form", function() { const keyString = key.val(); const chan = utils.findCurrentNetworkChan(channelString); if (chan.length) { - chan.click(); + chan.trigger("click"); } else { socket.emit("input", { text: `/join ${channelString} ${keyString}`, diff --git a/client/js/keybinds.js b/client/js/keybinds.js index 93a431f0..c4dcb471 100644 --- a/client/js/keybinds.js +++ b/client/js/keybinds.js @@ -14,7 +14,7 @@ Mousetrap.bind([ let container = windows.find(".window.active"); // Chat windows scroll message container - if (container.attr("id") === "chat-container") { + if (container.prop("id") === "chat-container") { container = container.find(".chan.active .chat"); } diff --git a/client/js/libs/jquery/stickyscroll.js b/client/js/libs/jquery/stickyscroll.js index fa83f688..aad7b8b3 100644 --- a/client/js/libs/jquery/stickyscroll.js +++ b/client/js/libs/jquery/stickyscroll.js @@ -2,7 +2,7 @@ import jQuery from "jquery"; (function($) { $.fn.unsticky = function() { - return this.trigger("unstick.sticky").unbind(".sticky"); + return this.trigger("unstick.sticky").off(".sticky"); }; $.fn.sticky = function() { diff --git a/client/js/lounge.js b/client/js/lounge.js index cc267a87..4a75f12e 100644 --- a/client/js/lounge.js +++ b/client/js/lounge.js @@ -44,7 +44,7 @@ $(function() { viewport.on("click", ".rt", function(e) { var self = $(this); - viewport.toggleClass(self.attr("class")); + viewport.toggleClass(self.prop("class")); e.stopPropagation(); chat.find(".chan.active .chat").trigger("msg.sticky"); }); @@ -216,7 +216,7 @@ $(function() { if (!("ontouchstart" in window || navigator.maxTouchPoints > 0)) { focus = function() { if (chat.find(".active").hasClass("chan")) { - input.focus(); + input.trigger("focus"); } }; @@ -297,14 +297,14 @@ $(function() { utils.setNick(sidebar.find(".chan.active").closest(".network").data("nick")); } - $("#nick-value").keypress(function(e) { + $("#nick-value").on("keypress", function(e) { switch (e.keyCode ? e.keyCode : e.which) { case 13: // Enter // Ensures a new line is not added when pressing Enter e.preventDefault(); break; } - }).keyup(function(e) { + }).on("keyup", function(e) { switch (e.keyCode ? e.keyCode : e.which) { case 13: // Enter submitNick(); @@ -320,7 +320,7 @@ $(function() { var chan = utils.findCurrentNetworkChan(name); if (chan.length) { - chan.click(); + chan.trigger("click"); } else { socket.emit("input", { target: chat.data("id"), @@ -402,7 +402,7 @@ $(function() { if (type === "channel" || type === "query") { placeholder = `Write to ${chan.data("title")}`; } - input.attr("placeholder", placeholder).attr("aria-label", placeholder); + input.prop("placeholder", placeholder).prop("aria-label", placeholder); if (self.hasClass("chan")) { $("#chat-container").addClass("active"); @@ -440,8 +440,8 @@ $(function() { } const state = {}; - if (self.attr("id")) { - state.clickTarget = `#${self.attr("id")}`; + if (self.prop("id")) { + state.clickTarget = `#${self.prop("id")}`; } else if (self.hasClass("chan")) { state.clickTarget = `#sidebar .chan[data-id="${self.data("id")}"]`; } else { @@ -506,7 +506,7 @@ $(function() { closeChan($(`.networks .chan[data-target="${itemData}"]`)); }, focusChan: function(itemData) { - $(`.networks .chan[data-target="${itemData}"]`).click(); + $(`.networks .chan[data-target="${itemData}"]`).trigger("click"); }, list: function(itemData) { socket.emit("input", { @@ -524,7 +524,7 @@ $(function() { const chan = utils.findCurrentNetworkChan(itemData); if (chan.length) { - chan.click(); + chan.trigger("click"); } socket.emit("input", { @@ -532,13 +532,13 @@ $(function() { text: "/whois " + itemData, }); - $(`.channel.active .users .user[data-name="${itemData}"]`).click(); + $(`.channel.active .users .user[data-name="${itemData}"]`).trigger("click"); }, query: function(itemData) { const chan = utils.findCurrentNetworkChan(itemData); if (chan.length) { - chan.click(); + chan.trigger("click"); } socket.emit("input", { diff --git a/client/js/options.js b/client/js/options.js index 8b74bef9..5c143c15 100644 --- a/client/js/options.js +++ b/client/js/options.js @@ -22,7 +22,7 @@ const options = { notifyAllMessages: false, showSeconds: false, statusMessages: "condensed", - theme: $("#theme").attr("href").replace(/^themes\/(.*).css$/, "$1"), // Extracts default theme name, set on the server configuration + theme: $("#theme").prop("href").replace(/^themes\/(.*).css$/, "$1"), // Extracts default theme name, set on the server configuration media: true, userStyles: userStyles.text(), }; @@ -66,7 +66,7 @@ module.exports.initialize = () => { settings.find(`input[name=${i}][value=${options[i]}]`) .prop("checked", true); } else if (i === "theme") { - $("#theme").attr("href", "themes/" + options[i] + ".css"); + $("#theme").prop("href", "themes/" + options[i] + ".css"); settings.find("select[name=" + i + "]").val(options[i]); } else if (options[i]) { settings.find("input[name=" + i + "]").prop("checked", true); @@ -83,14 +83,14 @@ module.exports.initialize = () => { // checkbox state can not be changed). const updateDesktopNotificationStatus = function() { if (Notification.permission === "denied") { - desktopNotificationsCheckbox.attr("disabled", true); - desktopNotificationsCheckbox.attr("checked", false); + desktopNotificationsCheckbox.prop("disabled", true); + desktopNotificationsCheckbox.prop("checked", false); warningBlocked.show(); } else { if (Notification.permission === "default" && desktopNotificationsCheckbox.prop("checked")) { - desktopNotificationsCheckbox.attr("checked", false); + desktopNotificationsCheckbox.prop("checked", false); } - desktopNotificationsCheckbox.attr("disabled", false); + desktopNotificationsCheckbox.prop("disabled", false); warningBlocked.hide(); } }; @@ -102,14 +102,14 @@ module.exports.initialize = () => { windows.on("show", "#settings", updateDesktopNotificationStatus); } else { options.desktopNotifications = false; - desktopNotificationsCheckbox.attr("disabled", true); - desktopNotificationsCheckbox.attr("checked", false); + desktopNotificationsCheckbox.prop("disabled", true); + desktopNotificationsCheckbox.prop("checked", false); } settings.on("change", "input, select, textarea", function() { const self = $(this); - const type = self.attr("type"); - const name = self.attr("name"); + const type = self.prop("type"); + const name = self.prop("name"); if (type === "password") { return; @@ -133,7 +133,7 @@ module.exports.initialize = () => { } else if (name === "coloredNicks") { chat.toggleClass("colored-nicks", self.prop("checked")); } else if (name === "theme") { - $("#theme").attr("href", "themes/" + options[name] + ".css"); + $("#theme").prop("href", "themes/" + options[name] + ".css"); } else if (name === "userStyles") { userStyles.html(options[name]); } else if (name === "highlights") { diff --git a/client/js/render.js b/client/js/render.js index 17772d82..c85e380e 100644 --- a/client/js/render.js +++ b/client/js/render.js @@ -163,7 +163,7 @@ function renderChannelUsers(data) { const search = users .find(".search") - .attr("placeholder", nicks.length + " " + (nicks.length === 1 ? "user" : "users")); + .prop("placeholder", nicks.length + " " + (nicks.length === 1 ? "user" : "users")); users .data("nicks", nicks) @@ -204,7 +204,7 @@ function renderNetworks(data, singleNetwork) { .data("needsNamesRefresh", true) .find(".header .topic") .html(helpers_parse(channel.topic)) - .attr("title", channel.topic); + .prop("title", channel.topic); } if (channel.messages.length > 0) { @@ -277,10 +277,10 @@ function loadMoreHistory(entries) { var target = $(entry.target).find(".show-more-button"); - if (target.attr("disabled")) { + if (target.prop("disabled")) { return; } - target.click(); + target.trigger("click"); }); } diff --git a/client/js/renderPreview.js b/client/js/renderPreview.js index 98d2f9ac..a6cb01a9 100644 --- a/client/js/renderPreview.js +++ b/client/js/renderPreview.js @@ -72,7 +72,7 @@ $("#chat").on("click", ".text .toggle-button", function() { // See https://github.com/thelounge/lounge/issues/1377 socket.emit("msg:preview:toggle", { target: parseInt(self.closest(".chan").data("id"), 10), - msgId: parseInt(self.closest(".msg").attr("id").replace("msg-", ""), 10), + msgId: parseInt(self.closest(".msg").prop("id").replace("msg-", ""), 10), link: self.data("url"), shown: content.hasClass("show"), }); @@ -111,7 +111,7 @@ Mousetrap.bind("esc", () => closeImageViewer()); Mousetrap.bind(["left", "right"], (e, key) => { if (imageViewer.hasClass("opened")) { const direction = key === "left" ? "previous" : "next"; - imageViewer.find(`.${direction}-image-btn`).click(); + imageViewer.find(`.${direction}-image-btn`).trigger("click"); } }); @@ -144,8 +144,8 @@ function openImageViewer(link, {pushState = true} = {}) { nextImage.addClass("next-image"); imageViewer.html(templates.image_viewer({ - image: link.find("img").attr("src"), - link: link.attr("href"), + image: link.find("img").prop("src"), + link: link.prop("href"), type: link.parent().hasClass("toggle-type-link") ? "link" : "image", hasPreviousImage: previousImage.length > 0, hasNextImage: nextImage.length > 0, @@ -164,20 +164,20 @@ function openImageViewer(link, {pushState = true} = {}) { // preview, e.g. changelog). This is sub-optimal and needs improvement to // make image preview more generic and not specific for channel previews. if (link.closest(".msg").length > 0) { - clickTarget = `#${link.closest(".msg").attr("id")} `; + clickTarget = `#${link.closest(".msg").prop("id")} `; } - clickTarget += `a.toggle-thumbnail[href="${link.attr("href")}"] img`; + clickTarget += `a.toggle-thumbnail[href="${link.prop("href")}"] img`; history.pushState({clickTarget}, null, null); } } imageViewer.on("click", ".previous-image-btn", function() { - $(".previous-image").click(); + $(".previous-image").trigger("click"); return false; }); imageViewer.on("click", ".next-image-btn", function() { - $(".next-image").click(); + $(".next-image").trigger("click"); return false; }); @@ -188,7 +188,7 @@ function closeImageViewer({pushState = true} = {}) { imageViewer.empty(); }); - input.focus(); + input.trigger("focus"); // History management if (pushState) { diff --git a/client/js/socket-events/auth.js b/client/js/socket-events/auth.js index 32193bda..3dfb48e4 100644 --- a/client/js/socket-events/auth.js +++ b/client/js/socket-events/auth.js @@ -26,7 +26,7 @@ socket.on("auth", function(data) { login.find("form").on("submit", function() { const form = $(this); - form.find(".btn").attr("disabled", true); + form.find(".btn").prop("disabled", true); const values = {}; $.each(form.serializeArray(), function(i, obj) { diff --git a/client/js/socket-events/changelog.js b/client/js/socket-events/changelog.js index 34149fbf..983b15f3 100644 --- a/client/js/socket-events/changelog.js +++ b/client/js/socket-events/changelog.js @@ -24,7 +24,7 @@ socket.on("changelog", function(data) { const links = $("#changelog .changelog-text a"); // Make sure all links will open a new tab instead of exiting the application - links.attr("target", "_blank"); + links.prop("target", "_blank"); // Add required metadata to image links, to support built-in image viewer links.has("img").addClass("toggle-thumbnail"); @@ -64,6 +64,6 @@ $("#help").on("click", "#check-now", () => { // Given a status and latest release information, update the version checker // (CSS class and content) function renderVersionChecker({status, latest}) { - $("#version-checker").attr("class", status) + $("#version-checker").prop("class", status) .html(templates.version_checker({latest, status})); } diff --git a/client/js/socket-events/configuration.js b/client/js/socket-events/configuration.js index 4d8f8309..17352969 100644 --- a/client/js/socket-events/configuration.js +++ b/client/js/socket-events/configuration.js @@ -31,7 +31,7 @@ socket.on("configuration", function(data) { const form = $(this); const event = form.data("event"); - form.find(".btn").attr("disabled", true); + form.find(".btn").prop("disabled", true); const values = {}; $.each(form.serializeArray(), function(i, obj) { diff --git a/client/js/socket-events/join.js b/client/js/socket-events/join.js index 6aae14da..71ddfc29 100644 --- a/client/js/socket-events/join.js +++ b/client/js/socket-events/join.js @@ -32,5 +32,5 @@ socket.on("join", function(data) { return $(a).data("id") - $(b).data("id"); }) .last() - .click(); + .trigger("click"); }); diff --git a/client/js/socket-events/more.js b/client/js/socket-events/more.js index e8760253..20460ca4 100644 --- a/client/js/socket-events/more.js +++ b/client/js/socket-events/more.js @@ -99,7 +99,7 @@ chat.on("click", ".show-more-button", function() { let lastMessageId = -1; if (lastMessage.length > 0) { - lastMessageId = parseInt(lastMessage.attr("id").replace("msg-", ""), 10); + lastMessageId = parseInt(lastMessage.prop("id").replace("msg-", ""), 10); } self diff --git a/client/js/socket-events/msg.js b/client/js/socket-events/msg.js index dea50413..c8a10d94 100644 --- a/client/js/socket-events/msg.js +++ b/client/js/socket-events/msg.js @@ -58,7 +58,7 @@ function processReceivedMessage(data) { render.appendMessage( container, targetId, - channel.attr("data-type"), + channel.prop("data-type"), data.msg ); @@ -172,7 +172,7 @@ function notifyMessage(targetId, channel, msg) { }); notify.addEventListener("click", function() { window.focus(); - button.click(); + button.trigger("click"); this.close(); }); } diff --git a/client/js/socket-events/part.js b/client/js/socket-events/part.js index e167653e..192c157b 100644 --- a/client/js/socket-events/part.js +++ b/client/js/socket-events/part.js @@ -9,7 +9,10 @@ socket.on("part", function(data) { // When parting from the active channel/query, jump to the network's lobby if (chanMenuItem.hasClass("active")) { - chanMenuItem.parent(".network").find(".lobby").click(); + chanMenuItem + .parent(".network") + .find(".lobby") + .trigger("click"); } chanMenuItem.remove(); diff --git a/client/js/socket-events/topic.js b/client/js/socket-events/topic.js index df16f263..e9284bdc 100644 --- a/client/js/socket-events/topic.js +++ b/client/js/socket-events/topic.js @@ -7,6 +7,6 @@ const helpers_parse = require("../libs/handlebars/parse"); socket.on("topic", function(data) { const topic = $("#chan-" + data.chan).find(".header .topic"); topic.html(helpers_parse(data.topic)); - // .attr() is safe escape-wise but consider the capabilities of the attribute - topic.attr("title", data.topic); + // .prop() is safe escape-wise but consider the capabilities of the attribute + topic.prop("title", data.topic); }); diff --git a/client/js/utils.js b/client/js/utils.js index 90bafd2a..2203cf3e 100644 --- a/client/js/utils.js +++ b/client/js/utils.js @@ -51,7 +51,7 @@ function isOpInChannel(channel) { // Triggering click event opens the virtual keyboard on mobile // This can only be called from another interactive event (e.g. button click) function forceFocus() { - input.trigger("click").focus(); + input.trigger("click").trigger("focus"); } function collapse() { @@ -69,14 +69,14 @@ function join(args) { if (channel) { const chan = findCurrentNetworkChan(channel); if (chan.length) { - chan.click(); + chan.trigger("click"); } } } function toggleNickEditor(toggle) { $("#nick").toggleClass("editable", toggle); - $("#nick-value").attr("contenteditable", toggle); + $("#nick-value").prop("contenteditable", toggle); } function setNick(nick) { @@ -92,8 +92,8 @@ const favicon = $("#favicon"); function toggleNotificationMarkers(newState) { // Toggles the favicon to red when there are unread notifications if (favicon.data("toggled") !== newState) { - var old = favicon.attr("href"); - favicon.attr("href", favicon.data("other")); + var old = favicon.prop("href"); + favicon.prop("href", favicon.data("other")); favicon.data("other", old); favicon.data("toggled", newState); } diff --git a/client/js/webpush.js b/client/js/webpush.js index 2423ec60..791b079a 100644 --- a/client/js/webpush.js +++ b/client/js/webpush.js @@ -11,7 +11,7 @@ let applicationServerKey; if ("serviceWorker" in navigator) { navigator.serviceWorker.addEventListener("message", (event) => { if (event.data && event.data.type === "open") { - $("#sidebar").find(`.chan[data-target="#${event.data.channel}"]`).click(); + $("#sidebar").find(`.chan[data-target="#${event.data.channel}"]`).trigger("click"); } }); } @@ -24,14 +24,14 @@ module.exports.configurePushNotifications = (subscribedOnServer, key) => { // If client has push registration but the server knows nothing about it, // this subscription is broken and client has to register again if (clientSubscribed === true && subscribedOnServer === false) { - pushNotificationsButton.attr("disabled", true); + pushNotificationsButton.prop("disabled", true); navigator.serviceWorker.ready .then((registration) => registration.pushManager.getSubscription()) .then((subscription) => subscription && subscription.unsubscribe()) .then((successful) => { if (successful) { - alternatePushButton().removeAttr("disabled"); + alternatePushButton().prop("disabled", false); } }); } @@ -58,7 +58,7 @@ module.exports.initialize = () => { $("#pushNotificationsUnsupported").hide(); pushNotificationsButton - .removeAttr("disabled") + .prop("disabled", false) .on("click", onPushButton); clientSubscribed = !!subscription; @@ -74,7 +74,7 @@ module.exports.initialize = () => { }; function onPushButton() { - pushNotificationsButton.attr("disabled", true); + pushNotificationsButton.prop("disabled", true); navigator.serviceWorker.ready.then((registration) => registration.pushManager.getSubscription().then((existingSubscription) => { @@ -106,7 +106,7 @@ function onPushButton() { }); }).then((successful) => { if (successful) { - alternatePushButton().removeAttr("disabled"); + alternatePushButton().prop("disabled", false); } }) ).catch((err) => {