您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Remove undesired components from the ABC News web site.
// ==UserScript== // @name A Little ABC News // @namespace https://www.alittleresearch.com.au // @version 2025-05-03 // @description Remove undesired components from the ABC News web site. // @author Nick Sheppard // @license MIT // @contributionURL https://ko-fi.com/npsheppard // @match https://www.abc.net.au/news // @icon https://www.alittleresearch.com.au/sites/default/files/alriconbl-transbg-32x32.png // @grant none // ==/UserScript== /////////////////////////////////////////////////////////////////////////////// // Copyright (c) 2025 Nicholas Paul Sheppard. See README.md for details // // Buy me a Ko-Fi at https://ko-fi.com/npsheppard. /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// // // The ABC News site identifies some components by an ID, some by a class name, // and some not at all. Each key of the siteConf structure identifies a // component by (i) id if the key begins with #; (ii) class name if the key // begins with .; or (iii) the conents of an <h2> element otherwise. // // The value for each key controls how that component will be rendered. Options // are as follows: // // 'default': display as usual // 'hidden': do not display // 'compressed': show only the header, which can be expanded by clicking // 'expanded': the same as 'expandable', but starting in the expanded state // // Note that the compressed/expanded state isn't saved between visits; // re-loading the site resets the component to the state given here. // // This script ships with the settings that I prefer, but feel free to change // them to your liking. // /////////////////////////////////////////////////////////////////////////////// const siteConf = { // Top Stories '#topStories': 'default', // State Top Storeis '#stateTopStories': 'default', // the fixed copy of Just In that appears at the top right) '#justIn': 'default', // Today's Topics '#todaysTopics': 'expanded', // For You 'For You': 'compressed', // Local News '#localNews': 'default', // Video Shorts '#videoShorts': 'compressed', // More News '#moreNews': 'expanded', // Everyone's Talking About... '#theBigPicture': 'compressed', // Around Australia '#aroundAustralia': 'expanded', // Politics '#politics': 'expanded', // World '#world': 'expanded', // Business '#business': 'expanded', // Sport '#sport': 'expanded', // Lifestyle '#lifestyle': 'expanded', // Entertainment '#entertainment': 'expanded', // the floating copy of Just In box that sticks to the right when scrolling done '.Home_justin__mrrHu Home_justinSticky__EkueF': 'hidden', // the category headings that appear above each story '.Tag_container__7_5W6': 'default' }; (function() { 'use strict'; // apply the configured renderer for every component in siteConf for (const key of Object.keys(siteConf)) { switch (siteConf[key]) { case 'hidden': applyRenderer(key, (element) => { renderHidden(element); }); break; case 'compressed': applyRenderer(key, (element) => { renderExpandable(element, true); }); break; case 'expanded': applyRenderer(key, (element) => { renderExpandable(element, false); }); break; case 'default': // do nothing break; default: console.log("Invalid value '" + siteConf[key] + "' for configuration key " + key); break; } } })(); // Apply a renderer to all of the elements matching a given key from the // siteConf structure. // // Input: // key - the key from the siteConf structure // render - a function taking a single DOMElement object as input function applyRenderer(key, render) { if (key.charAt(0) === "#") { // component identified by id const element = document.getElementById(key.substring(1, key.length)); if (element != null) { render(element); } } else if (key.charAt(0) === ".") { // component identified by class name const elements = document.getElementsByClassName(key.substring(1, key.length)); if (elements != null) { for (let i = 0; i < elements.length; i++) { render(elements[i]); } } } else { // component identified by <h2> const headings = document.getElementsByTagName("H2"); if (headings != null) { for (let i = 0; i < headings.length; i++) { if (headings[i].innerHTML === key) { render(findRailRoot(headings[i])); } } } } } // Find the root element of a rail component associated with a given // element. The rail component may either enclose the element, or be // contained within the element. // // Input: // element (DOMElement) - an element with the rail component // // Returns: the root element of the rail component, or null if no element is found function findRailRoot(element) { // first, search downwards for a rail component contained within the element let railRootElement = element; while (railRootElement != null && (!railRootElement.className == null || !railRootElement.className.startsWith("Rail_root__"))) { railRootElement = railRootElement.firstElementChild; } if (railRootElement != null) { return railRootElement; } // now search upwards for a rail component containing the element railRootElement = element; while (railRootElement != null && (!railRootElement.className == null || !railRootElement.className.startsWith("Rail_root__"))) { railRootElement = railRootElement.parentElement; } return railRootElement; } // Hide a component by setting its display style to "none". // // Input: // element (DOMElement) - the DOM element at the root of the component to be suppressed // function renderHidden(element) { element.style.display = "none"; } // Make a "rail" component expandable. In the expanded state, the component // displays as usual, but its header region changes colour when the cursor // hovers over it. When clicked, the contents are hidden. Similarly, clicking // on the header region in the compressed state re-expands the component. // // The general structure of a rail component is as follows, where the xxxxx's // are code that differs from component to component but has no obvious // meaning. // // // <div id="..." or class="..."> // <!-- sometimes a div contains the Rail_root --> // <div class="Rail_root__xxxxx Rail_sideScrolling__xxxxx"> // <div class="Rail_header__xxxxx"> // <h2>...</h2> // <div>...</div> // </div> // <div class="Rail_scollNavigation__xxxxx"> // <button title="Move left"><svg .../></button> // <button title="Move right"><svg .../></button> // </div> // <div class="Rail_content__xxxxx"> // <ul .../> // </div> // </div> // <!-- end of optional containing div --> // </div> // // Input: // element (DOMElement) - the root element of the rail component to be suppressed // startCompressed (boolean) - true to start in the compressed state; false to start in the expanded state function renderExpandable(element, startCompressed = false) { // find the rail root let railRootElement = findRailRoot(element); if (railRootElement == null) { // couldn't find the rail root; bail out console.log("Couldn't find the rail root for " + element); return; } // get the components of the rail root let railHeaderElement = null; let railNavigationElement = null; let railContentElement = null; let railChild = railRootElement.firstElementChild; while (railChild != null) { if(railChild.className != null) { if (railChild.className.startsWith("Rail_header__")) { railHeaderElement = railChild; } else if (railChild.className.startsWith("Rail_scollNavigation__")) { railNavigationElement = railChild; } else if (railChild.className.startsWith("Rail_content__")) { railContentElement = railChild; } } railChild = railChild.nextElementSibling; } // suppress display of the rail content if (railContentElement != null) { railContentElement.style.display = startCompressed ? "none" : ""; if (railHeaderElement != null) { railHeaderElement.style.cursor = "zoom-in"; railHeaderElement.style.borderRadius = "8px"; railHeaderElement.onclick = function () { if (railContentElement.style.display === "none") { railContentElement.style.display = "block"; railHeaderElement.style.cursor = "zoom-out"; } else { railContentElement.style.display = "none"; railHeaderElement.style.cursor = "zoom-in"; } }; railHeaderElement.onmouseover = function() { railHeaderElement.style.backgroundColor = 'var(--nw-colour-theme-surface-tint)'; }; railHeaderElement.onmouseout = function() { railHeaderElement.style.backgroundColor = 'white'; }; } } }