feedkeeper 0.35.7 → 0.35.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -3,6 +3,7 @@ import { EMBED_RULES, resolveEmbeds } from "./embeds/index.js";
|
|
|
3
3
|
import { embedHeadings } from "./embeds/headings.js";
|
|
4
4
|
import { boilerplate } from "./noise/boilerplate.js";
|
|
5
5
|
import { loadingPlaceholders } from "./noise/loading.js";
|
|
6
|
+
import { pageChrome } from "./noise/pageChrome.js";
|
|
6
7
|
import { trackingPixels } from "./noise/pixels.js";
|
|
7
8
|
import { permalinkGlyphs } from "./noise/permalinkGlyphs.js";
|
|
8
9
|
import { sidebars } from "./noise/sidebars.js";
|
|
@@ -12,7 +13,7 @@ import { teaserLinks } from "./noise/teaserLinks.js";
|
|
|
12
13
|
* tags that are removed next), then the clutter around the story. The tests check each rule against its fixtures in
|
|
13
14
|
* `test/fixtures/content/<rule name>` and that running it twice changes nothing. See `docs/content-rules.md`.
|
|
14
15
|
*/
|
|
15
|
-
export const PAGE_RULES = [lazyImages, ...EMBED_RULES, embedHeadings, sidebars, loadingPlaceholders, trackingPixels, boilerplate, teaserLinks, permalinkGlyphs];
|
|
16
|
+
export const PAGE_RULES = [lazyImages, ...EMBED_RULES, embedHeadings, pageChrome, sidebars, loadingPlaceholders, trackingPixels, boilerplate, teaserLinks, permalinkGlyphs];
|
|
16
17
|
export { resolveEmbeds };
|
|
17
18
|
/** What a fetched page goes through before its scripts, frames and `noscript` blocks are removed. */
|
|
18
19
|
export function cleanPage(root, stats = {}) {
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { count, flat, pruneEmpty } from "../shared.js";
|
|
2
|
+
/** A paragraph this long is prose, not a menu entry: an element that holds one is never page chrome, whatever it is called. */
|
|
3
|
+
const PROSE_CHARACTERS = 200;
|
|
4
|
+
/** What only a site's own navigation contains. */
|
|
5
|
+
const NAVIGATION = "nav, [role='navigation'], [role='menubar'], menu";
|
|
6
|
+
/** A page header holds the site's navigation, or even the page's main area; an article's own header holds a headline and a byline. */
|
|
7
|
+
const PAGE_HEADER_PARTS = `${NAVIGATION}, main`;
|
|
8
|
+
function holdsProse(element) {
|
|
9
|
+
return [...element.querySelectorAll("p")].some(paragraph => flat(paragraph.textContent).length >= PROSE_CHARACTERS);
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Some publishers put their whole page header into the text of an article: a menu of magazines with empty entries
|
|
13
|
+
* (their icons are drawn by a stylesheet), service links, the logo and lists of the publisher's other pages. A reader
|
|
14
|
+
* shows all of it before the first line of the story. A header that contains navigation, and any navigation of its own, are
|
|
15
|
+
* the site and not the story: they go, unless prose sits inside, which means the markup is broken and wraps the article.
|
|
16
|
+
*/
|
|
17
|
+
export const pageChrome = {
|
|
18
|
+
name: "page-chrome",
|
|
19
|
+
description: "A page header that holds the site's navigation, and any navigation element, are removed from the text of an article.",
|
|
20
|
+
apply(root, stats) {
|
|
21
|
+
let changed = false;
|
|
22
|
+
const remove = (element) => {
|
|
23
|
+
if (!element.parentNode || holdsProse(element))
|
|
24
|
+
return;
|
|
25
|
+
const parent = element.parentNode;
|
|
26
|
+
element.remove();
|
|
27
|
+
pruneEmpty(parent);
|
|
28
|
+
count(stats, "page-chrome");
|
|
29
|
+
changed = true;
|
|
30
|
+
};
|
|
31
|
+
for (const header of [...root.querySelectorAll("header")].filter(candidate => candidate.querySelector(PAGE_HEADER_PARTS)))
|
|
32
|
+
remove(header);
|
|
33
|
+
for (const navigation of [...root.querySelectorAll(NAVIGATION)])
|
|
34
|
+
remove(navigation);
|
|
35
|
+
return changed;
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
//# sourceMappingURL=pageChrome.js.map
|
|
@@ -7,6 +7,7 @@ import { SIDEBAR_HEADINGS } from "./content/patterns/sidebars/index.js";
|
|
|
7
7
|
import { resolveEmbeds } from "./content/embeds/index.js";
|
|
8
8
|
import { loadingPlaceholders } from "./content/noise/loading.js";
|
|
9
9
|
import { trackingPixels } from "./content/noise/pixels.js";
|
|
10
|
+
import { pageChrome } from "./content/noise/pageChrome.js";
|
|
10
11
|
import { permalinkGlyphs } from "./content/noise/permalinkGlyphs.js";
|
|
11
12
|
import { teaserLinks } from "./content/noise/teaserLinks.js";
|
|
12
13
|
import { markVideoTeasers } from "./content/noise/videoTeasers.js";
|
|
@@ -102,6 +103,8 @@ function removeReaderNoise(root, title, stats, author) {
|
|
|
102
103
|
changed = true;
|
|
103
104
|
if (trackingPixels.apply(root, stats))
|
|
104
105
|
changed = true;
|
|
106
|
+
if (pageChrome.apply(root, stats))
|
|
107
|
+
changed = true;
|
|
105
108
|
for (const selector of BREADCRUMB_MARKERS) {
|
|
106
109
|
try {
|
|
107
110
|
root.querySelectorAll(selector).forEach(element => drop(element, "breadcrumb"));
|