From 6d3619724735cad09bcb24110403d21479d1fd4d Mon Sep 17 00:00:00 2001 From: supahgreg Date: Tue, 14 Oct 2025 22:43:09 +0000 Subject: Remove various Element and Array prototype extensions (and similar). --- js/App.js | 20 +++----- js/Article.js | 27 +++++----- js/CommonFilters.js | 4 +- js/FeedTree.js | 4 +- js/Feeds.js | 2 +- js/Headlines.js | 103 +++++++++++++++++---------------------- js/PrefFeedTree.js | 10 ++-- js/common.js | 91 ++++++++-------------------------- js/utility.js | 4 +- plugins/share/share.js | 18 ++----- plugins/shorten_expanded/init.js | 5 +- 11 files changed, 99 insertions(+), 189 deletions(-) diff --git a/js/App.js b/js/App.js index e82e45d0c..b88c08062 100644 --- a/js/App.js +++ b/js/App.js @@ -210,7 +210,7 @@ const App = { if (callback) { link.onload = function() { - document.querySelector("body").removeClassName("css_loading"); + document.body.classList.remove('css_loading'); callback(); }; @@ -221,9 +221,9 @@ const App = { this.nightModeChanged(mql.matches, link); - document.querySelector("head").appendChild(link); + document.head.appendChild(link); } else { - document.querySelector("body").removeClassName("css_loading"); + document.body.classList.remove('css_loading'); if (callback) callback(); } @@ -1238,15 +1238,11 @@ const App = { this.hotkey_actions["goto_prefs"] = () => { App.openPreferences(); }; - this.hotkey_actions["select_article_cursor"] = () => { - const id = Article.getUnderPointer(); - if (id) { - const row = App.byId(`RROW-${id}`); - - if (row) - row.toggleClassName("Selected"); - } - }; + this.hotkey_actions['select_article_cursor'] = () => { + const id = Article.getUnderPointer(); + if (id) + App.byId(`RROW-${id}`)?.classList.toggle('Selected'); + }; this.hotkey_actions["create_label"] = () => { CommonDialogs.addLabel(); }; diff --git a/js/Article.js b/js/Article.js index 67de59aea..a9684c755 100644 --- a/js/Article.js +++ b/js/Article.js @@ -48,11 +48,11 @@ const Article = { ["score-low", "score-high", "score-half-low", "score-half-high", "score-neutral"] .forEach(function(scl) { - if (row.hasClassName(scl)) - row.removeClassName(scl); + if (row.classList.contains(scl)) + row.classList.remove(scl); }); - row.addClassName(Article.getScoreClass(score)); + row.classList.add(Article.getScoreClass(score)); } }); } @@ -76,13 +76,8 @@ const Article = { pic.innerHTML = Article.getScorePic(score); pic.setAttribute("title", score); - ["score-low", "score-high", "score-half-low", "score-half-high", "score-neutral"] - .forEach(function(scl) { - if (row.hasClassName(scl)) - row.removeClassName(scl); - }); - - row.addClassName(Article.getScoreClass(score)); + row.classList.remove('score-low', 'score-high', 'score-half-low', 'score-half-high', 'score-neutral'); + row.classList.add(Article.getScoreClass(score)); } } }, @@ -96,7 +91,7 @@ const Article = { const row = App.byId(`RROW-${id}`); if (row) { - row.toggleClassName('grid-span-row'); + row.classList.toggle('grid-span-row'); this.setActive(id); this.cdmMoveToId(id); @@ -106,7 +101,7 @@ const Article = { const row = App.byId(`RROW-${Article.getActive()}`); if (row) { - row.removeClassName("active"); + row.classList.remove('active'); if (event) event.stopPropagation(); @@ -263,7 +258,7 @@ const Article = { container.innerHTML += " "; // in expandable mode, save content for later, so that we can pack unfocused rows back - if (App.isCombinedMode() && App.byId("main").hasClassName("expandable")) + if (App.isCombinedMode() && App.byId('main').classList.contains('expandable')) row.setAttribute("data-content-original", row.getAttribute("data-content")); row.setAttribute("data-is-packed", "0"); @@ -431,7 +426,7 @@ const Article = { console.log("setActive", id, "was", Article.getActive()); App.findAll("div[id*=RROW][class*=active]").forEach((row) => { - row.removeClassName("active"); + row.classList.remove('active'); if (App.isCombinedMode() && !App.getInitParam("cdm_expanded")) Article.pack(row); @@ -442,8 +437,8 @@ const Article = { if (row) { Article.unpack(row); - row.removeClassName("Unread"); - row.addClassName("active"); + row.classList.remove('Unread'); + row.classList.add('active'); PluginHost.run(PluginHost.HOOK_ARTICLE_SET_ACTIVE, parseInt(row.getAttribute('data-article-id'))); } diff --git a/js/CommonFilters.js b/js/CommonFilters.js index 54df70266..460107c58 100644 --- a/js/CommonFilters.js +++ b/js/CommonFilters.js @@ -109,7 +109,7 @@ const Filters = { xhr.post("backend.php", {op: "Pref_Filters", method: "printrulename", rule: rule}, (reply) => { try { const li = document.createElement('li'); - li.addClassName("rule"); + li.classList.add('rule'); li.innerHTML = `${App.FormFields.checkbox_tag("", false, "", {onclick: 'Lists.onRowChecked(this)'})} ${reply} @@ -141,7 +141,7 @@ const Filters = { xhr.post("backend.php", { op: "Pref_Filters", method: "printactionname", action: action }, (reply) => { try { const li = document.createElement('li'); - li.addClassName("action"); + li.classList.add('action'); li.innerHTML = `${App.FormFields.checkbox_tag("", false, "", {onclick: 'Lists.onRowChecked(this)'})} ${reply} diff --git a/js/FeedTree.js b/js/FeedTree.js index 01755e7b4..4e6bac8a6 100755 --- a/js/FeedTree.js +++ b/js/FeedTree.js @@ -360,11 +360,11 @@ define(["dojo/_base/declare", "dojo/dom-construct", "dojo/_base/array", "dojo/co treeNode = treeNode[0]; if (show) { - treeNode.loadingNode.addClassName("visible"); + treeNode.loadingNode.classList.add('visible'); treeNode.loadingNode.setAttribute("src", is_cat ? App.getInitParam("icon_three_dots") : App.getInitParam("icon_oval")); } else { - treeNode.loadingNode.removeClassName("visible"); + treeNode.loadingNode.classList.remove('visible'); treeNode.loadingNode.setAttribute("src", App.getInitParam("icon_blank")) } diff --git a/js/Feeds.js b/js/Feeds.js index 790b64dd4..29ae72558 100644 --- a/js/Feeds.js +++ b/js/Feeds.js @@ -535,7 +535,7 @@ const Feeds = { const rows = App.findAll("#headlines-frame > div[id*=RROW][class*=Unread][data-orig-feed-id='" + id + "']"); rows.forEach((row) => { - row.removeClassName("Unread"); + row.classList.remove('Unread'); }) } }, diff --git a/js/Headlines.js b/js/Headlines.js index 7ce1e63ba..1cc91f04a 100755 --- a/js/Headlines.js +++ b/js/Headlines.js @@ -67,15 +67,15 @@ const Headlines = { if (hl) { const hl_old = {...{}, ...hl}; - hl.unread = row.hasClassName("Unread"); - hl.marked = row.hasClassName("marked"); - hl.published = row.hasClassName("published"); + hl.unread = row.classList.contains('Unread'); + hl.marked = row.classList.contains('marked'); + hl.published = row.classList.contains('published'); // not sent by backend - hl.selected = row.hasClassName("Selected"); - hl.active = row.hasClassName("active"); + hl.selected = row.classList.contains('Selected'); + hl.active = row.classList.contains('active'); - hl.score = row.getAttribute("data-score"); + hl.score = row.getAttribute('data-score'); modified.push({id: hl.id, new: hl, old: hl_old, row: row}); } @@ -138,7 +138,7 @@ const Headlines = { ops.deselect.forEach((row) => { const cb = dijit.getEnclosingWidget(row.querySelector(".rchk")); - if (cb && !row.hasClassName("active")) + if (cb && !row.classList.contains('active')) cb.attr('checked', false); }); @@ -152,7 +152,7 @@ const Headlines = { ops.deactivate.forEach((row) => { const cb = dijit.getEnclosingWidget(row.querySelector(".rchk")); - if (cb && !row.hasClassName("Selected")) + if (cb && !row.classList.contains('Selected')) cb.attr('checked', false); }); @@ -376,7 +376,7 @@ const Headlines = { const row = rows[i]; if (App.byId("headlines-frame").scrollTop > (row.offsetTop + row.offsetHeight / 2)) { - row.removeClassName("Unread"); + row.classList.remove('Unread'); } else { break; } @@ -395,21 +395,19 @@ const Headlines = { setCommonClasses: function (headlines_count) { const container = App.byId("headlines-frame"); - container.removeClassName("cdm"); - container.removeClassName("normal"); + container.classList.remove('cdm', 'normal'); - container.addClassName(App.isCombinedMode() ? "cdm" : "normal"); + container.classList.add(App.isCombinedMode() ? 'cdm' : 'normal'); container.setAttribute("data-enable-grid", App.getInitParam("cdm_enable_grid") ? "true" : "false"); container.setAttribute("data-headlines-count", parseInt(headlines_count)); container.setAttribute("data-is-cdm", App.isCombinedMode() ? "true" : "false"); container.setAttribute("data-is-cdm-expanded", App.getInitParam("cdm_expanded")); // for floating title because it's placed outside of headlines-frame - App.byId("main").removeClassName("expandable"); - App.byId("main").removeClassName("expanded"); + App.byId('main').classList.remove('expandable', 'expanded'); if (App.isCombinedMode()) - App.byId("main").addClassName(App.getInitParam("cdm_expanded") ? "expanded" : "expandable"); + App.byId('main').classList.add(App.getInitParam('cdm_expanded') ? 'expanded' : 'expandable'); }, renderAgain: function () { // TODO: wrap headline elements into a knockoutjs model to prevent all this stuff @@ -425,7 +423,7 @@ const Headlines = { row.parentNode.replaceChild(new_row, row); if (hl.active) { - new_row.addClassName("active"); + new_row.classList.add('active'); Article.unpack(new_row); if (App.isCombinedMode()) @@ -773,9 +771,9 @@ const Headlines = { Article.setActive(0); try { - App.byId("headlines-frame").removeClassName("smooth-scroll"); - App.byId("headlines-frame").scrollTop = 0; - App.byId("headlines-frame").addClassName("smooth-scroll"); + App.byId('headlines-frame').classList.remove('smooth-scroll'); + App.byId('headlines-frame').scrollTop = 0; + App.byId('headlines-frame').classList.add('smooth-scroll'); } catch (e) { console.warn(e); } @@ -955,13 +953,13 @@ const Headlines = { if (row) { switch (cmode) { case 0: - row.removeClassName("Unread"); + row.classList.remove('Unread'); break; case 1: - row.addClassName("Unread"); + row.classList.add('Unread'); break; case 2: - row.toggleClassName("Unread"); + row.classList.toggle('Unread'); } } }); @@ -982,26 +980,18 @@ const Headlines = { ids = ids || Headlines.getSelected(); if (ids.length === 0) { - alert(__("No articles selected.")); + alert(__('No articles selected.')); return; } - ids.forEach((id) => { - this.togglePub(id); - }); + ids.forEach(id => this.togglePub(id)); }, toggleMark: function (id) { - const row = App.byId(`RROW-${id}`); - - if (row) - row.toggleClassName("marked"); + App.byId(`RROW-${id}`)?.classList.toggle('marked'); }, togglePub: function (id) { - const row = App.byId(`RROW-${id}`); - - if (row) - row.toggleClassName("published"); + App.byId(`RROW-${id}`)?.classList.toggle('published'); }, move: function (mode, params = {}) { const no_expand = params.no_expand || false; @@ -1110,13 +1100,13 @@ const Headlines = { switch (cmode) { case 0: - row.removeClassName("Unread"); + row.classList.remove('Unread'); break; case 1: - row.addClassName("Unread"); + row.classList.add('Unread'); break; case 2: - row.toggleClassName("Unread"); + row.classList.toggle('Unread'); break; } } @@ -1186,18 +1176,15 @@ const Headlines = { }); }, getSelected: function () { - const rv = []; + const selected = App.findAll("#headlines-frame > div[id*=RROW][class*=Selected]") + .map(child => parseInt(child.getAttribute('data-article-id'))); - App.findAll("#headlines-frame > div[id*=RROW][class*=Selected]").forEach( - function (child) { - rv.push(parseInt(child.getAttribute('data-article-id'))); - }); + const active = Article.getActive(); - // consider active article a honorary member of selected articles - if (Article.getActive()) - rv.push(Article.getActive()); + if (active) + selected.push(active); - return rv.uniq(); + return [...new Set(selected)]; }, getLoaded: function () { const rv = []; @@ -1216,15 +1203,15 @@ const Headlines = { const row = elem.domNode.closest("div[id*=RROW]"); // do not allow unchecking active article checkbox - if (row.hasClassName("active")) { + if (row.classList.contains('active')) { elem.attr("checked", 1); return; } - if (elem.attr("checked")) { - row.addClassName("Selected"); + if (elem.attr('checked')) { + row.classList.add('Selected'); } else { - row.removeClassName("Selected"); + row.classList.remove('Selected'); } }, getRange: function (start, stop) { @@ -1281,14 +1268,14 @@ const Headlines = { App.findAll(query).forEach((row) => { switch (mode) { - case "none": - row.removeClassName("Selected"); + case 'none': + row.classList.remove('Selected'); break; - case "invert": - row.toggleClassName("Selected"); + case 'invert': + row.classList.toggle('Selected'); break; default: - row.addClassName("Selected"); + row.classList.add('Selected'); } }); }, @@ -1331,7 +1318,7 @@ const Headlines = { if (visible_ids[i] !== id) { const e = App.byId(`RROW-${visible_ids[i]}`); - if (e && e.hasClassName("Unread")) { + if (e && e.classList.contains('Unread')) { ids_to_mark.push(visible_ids[i]); } } else { @@ -1343,7 +1330,7 @@ const Headlines = { if (visible_ids[i] !== id) { const e = App.byId(`RROW-${visible_ids[i]}`); - if (e && e.hasClassName("Unread")) { + if (e && e.classList.contains('Unread')) { ids_to_mark.push(visible_ids[i]); } } else { @@ -1361,7 +1348,7 @@ const Headlines = { for (let i = 0; i < ids_to_mark.length; i++) { const e = App.byId(`RROW-${ids_to_mark[i]}`); - e.removeClassName("Unread"); + e.classList.remove('Unread'); } } } diff --git a/js/PrefFeedTree.js b/js/PrefFeedTree.js index 4e9cb58a5..5bb8830eb 100644 --- a/js/PrefFeedTree.js +++ b/js/PrefFeedTree.js @@ -337,13 +337,9 @@ define(["dojo/_base/declare", "dojo/dom-construct", "lib/CheckBoxTree", "dojo/_b target.attr('disabled', !checkbox.attr('checked')); console.log(target, target.attr('type')); - if (target.attr('type') === "checkbox") { - const label = checkbox.domNode.closest("label"); - - if (checkbox.attr('checked')) - label.removeClassName('text-muted'); - else - label.addClassName('text-muted'); + if (target.attr('type') === 'checkbox') { + const label = checkbox.domNode.closest('label'); + label.classList.toggle('text-muted', !checkbox.attr('checked')); } }, execute: function () { diff --git a/js/common.js b/js/common.js index 48a42b95a..b981f0141 100755 --- a/js/common.js +++ b/js/common.js @@ -48,45 +48,20 @@ window.cancelIdleCallback = clearTimeout(id); }; -Element.prototype.hasClassName = function(className) { - return this.classList.contains(className); -}; - -Element.prototype.addClassName = function(className) { - return this.classList.add(className); -}; - -Element.prototype.removeClassName = function(className) { - return this.classList.remove(className); -}; - -Element.prototype.toggleClassName = function(className) { - if (this.hasClassName(className)) - return this.removeClassName(className); - else - return this.addClassName(className); -}; - - Element.prototype.setStyle = function(args) { - Object.keys(args).forEach((k) => { - this.style[k] = args[k]; - }); + Object.assign(this.style, args); }; Element.prototype.show = function() { - this.style.display = ""; + this.style.display = ''; }; Element.prototype.hide = function() { - this.style.display = "none"; + this.style.display = 'none'; }; Element.prototype.toggle = function() { - if (this.visible()) - this.hide(); - else - this.show(); + this.visible() ? this.hide() : this.show(); }; // https://gist.github.com/alirezas/c4f9f43e9fe1abba9a4824dd6fc60a55 @@ -149,23 +124,6 @@ Element.toggle = function(elem) { return elem.toggle(); } -Element.hasClassName = function (elem, className) { - if (typeof elem === "string") - elem = document.getElementById(elem); - - return elem.hasClassName(className); -} - -Array.prototype.remove = function(s) { - for (let i=0; i < this.length; i++) { - if (s === this[i]) this.splice(i, 1); - } -}; - -Array.prototype.uniq = function() { - return this.filter((v, i, a) => a.indexOf(v) === i); -}; - /* exported xhr */ const xhr = { _ts: 0, @@ -269,14 +227,10 @@ function xhrJson(url, params = {}, complete = undefined) { /* exported Lists */ const Lists = { onRowChecked: function(elem) { - const checked = elem.domNode ? elem.attr("checked") : elem.checked; // account for dojo checkboxes + const checked = elem.domNode ? elem.attr('checked') : elem.checked; elem = elem.domNode || elem; - - const row = elem.closest("li"); - - if (row) - checked ? row.addClassName("Selected") : row.removeClassName("Selected"); + elem.closest('li')?.classList.toggle('Selected', checked); }, select: function(elem, selected) { if (typeof elem === "string") @@ -304,7 +258,7 @@ const Lists = { elem = document.getElementById(elem); elem.querySelectorAll("li").forEach((row) => { - if (row.hasClassName("Selected")) { + if (row.classList.contains('Selected')) { const rowVal = row.getAttribute("data-row-value"); if (rowVal) { @@ -327,14 +281,9 @@ const Lists = { const Tables = { onRowChecked: function(elem) { // account for dojo checkboxes - const checked = elem.domNode ? elem.attr("checked") : elem.checked; + const checked = elem.domNode ? elem.attr('checked') : elem.checked; elem = elem.domNode || elem; - - const row = elem.closest("tr"); - - if (row) - checked ? row.addClassName("Selected") : row.removeClassName("Selected"); - + elem.closest('tr')?.classList.toggle('Selected', checked); }, select: function(elem, selected) { if (typeof elem === "string") @@ -362,7 +311,7 @@ const Tables = { elem = document.getElementById(elem); elem.querySelectorAll("tr").forEach((row) => { - if (row.hasClassName("Selected")) { + if (row.classList.contains('Selected')) { const rowVal = row.getAttribute("data-row-value"); if (rowVal) { @@ -426,7 +375,7 @@ const Notify = { window.clearTimeout(this.timeout); if (!msg) { - notify.removeClassName("visible"); + notify.classList.remove('visible'); return; } @@ -439,19 +388,19 @@ const Notify = { switch (kind) { case this.KIND_INFO: - notify.addClassName("notify_info") - icon = "notifications"; + notify.classList.add('notify_info') + icon = 'notifications'; break; case this.KIND_ERROR: - notify.addClassName("notify_error"); - icon = "error"; + notify.classList.add('notify_error'); + icon = 'error'; break; case this.KIND_PROGRESS: - notify.addClassName("notify_progress"); - icon = App.getInitParam("icon_oval") + notify.classList.add('notify_progress'); + icon = App.getInitParam('icon_oval'); break; default: - icon = "notifications"; + icon = 'notifications'; } if (icon) @@ -464,11 +413,11 @@ const Notify = { __("Click to close") + "\" onclick=\"Notify.close()\">close"; notify.innerHTML = msgfmt; - notify.addClassName("visible"); + notify.classList.add('visible'); if (!keep) this.timeout = window.setTimeout(() => { - notify.removeClassName("visible"); + notify.classList.remove('visible'); }, this.default_timeout); }, diff --git a/js/utility.js b/js/utility.js index 0a9b59454..0fb08435c 100644 --- a/js/utility.js +++ b/js/utility.js @@ -26,9 +26,9 @@ window.addEventListener("load", function() { link.id = "theme_auto_css"; link.onload = function() { - document.querySelector("body").removeClassName("css_loading"); + document.body.classList.remove('css_loading'); - if (typeof UtilityApp !== "undefined") + if (typeof UtilityApp !== 'undefined') UtilityApp.init(); }; diff --git a/plugins/share/share.js b/plugins/share/share.js index f27e06678..0ae4b2031 100644 --- a/plugins/share/share.js +++ b/plugins/share/share.js @@ -23,10 +23,7 @@ Plugins.Share = { target.href = target.href.replace(/&key=.*$/, "&key=" + new_link); - const icon = document.querySelector(".share-icon-" + id); - - if (icon) - icon.addClassName("is-shared"); + document.querySelector('.share-icon-' + id)?.classList.add('is-shared'); Notify.close(); @@ -42,12 +39,7 @@ Plugins.Share = { if (confirm(__("Remove sharing for this article?"))) { xhr.post("backend.php", App.getPhArgs("share", "unshare", {id: id}), (reply) => { Notify.info(reply); - - const icon = document.querySelector(".share-icon-" + id); - - if (icon) - icon.removeClassName("is-shared"); - + document.querySelector('.share-icon-' + id)?.classList.remove('is-shared'); dialog.hide(); }); } @@ -61,11 +53,7 @@ Plugins.Share = { xhr.post("backend.php", App.getPhArgs("share", "shareDialog", {id: id}), (reply) => { dialog.attr('content', reply) - - const icon = document.querySelector(".share-icon-" + id); - - if (icon) - icon.addClassName("is-shared"); + document.querySelector('.share-icon-' + id)?.classList.add('is-shared'); }); }); diff --git a/plugins/shorten_expanded/init.js b/plugins/shorten_expanded/init.js index a89fe8e92..deb3b6393 100644 --- a/plugins/shorten_expanded/init.js +++ b/plugins/shorten_expanded/init.js @@ -55,10 +55,9 @@ Plugins.Shorten_Expanded = { const row = App.byId(id); if (row) { - const content = row.querySelector(".content-shrink-wrap"); - const link = row.querySelector(".expand-prompt"); + const link = row.querySelector('.expand-prompt'); - if (content) content.removeClassName("content-shrink-wrap"); + row.querySelector('.content-shrink-wrap')?.classList.remove('content-shrink-wrap'); if (link) Element.hide(link); } -- cgit v1.2.3-54-g00ecf