annotate js/feed-preview.js @ 6:5d7c13e998e9

Create feed previews using a stream filter Instead of replacing the feed document with an XHTML preview from a content script after it has already been rendered, create an XHTML preview using a stream filter before it is passed into the rendering engine and use an XSL style sheet to convert it to HTML. This has two advantages, firstly it results in an HTMLDocument with the full HTML DOM available and secondly it avoids rendering the document twice. Refactor the feed preview creation and split parsing and rendering into seperate modules.
author Guido Berhoerster <guido+feed-preview@berhoerster.name>
date Thu, 08 Nov 2018 16:30:34 +0100
parents
children fcd65cf3f634
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
6
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
1 /*
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
2 * Copyright (C) 2018 Guido Berhoerster <guido+feed-preview@berhoerster.name>
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
3 *
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
4 * This Source Code Form is subject to the terms of the Mozilla Public
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
7 */
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
8
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
9 'use strict';
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
10
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
11 export function renderFeedPreview(feedPreviewDocument, feed) {
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
12 // inject XSL stylesheet which transforms XHTML to HTML allowing the use of
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
13 // the HTML DOM
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
14 let xslFilename = browser.runtime.getURL('web_resources/xhtml-to-html.xsl');
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
15 let xmlStylesheetNode =
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
16 feedPreviewDocument.createProcessingInstruction('xml-stylesheet',
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
17 `type="application/xslt+xml" href="${xslFilename}"`);
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
18 feedPreviewDocument.firstChild.after(xmlStylesheetNode);
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
19
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
20 feedPreviewDocument.querySelector('link[rel=stylesheet]').href =
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
21 browser.runtime.getURL('web_resources/style/feed-preview.css');
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
22
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
23 feedPreviewDocument.querySelector('title').textContent = feed.title;
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
24 feedPreviewDocument.querySelector('#feed-title').textContent = feed.title;
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
25 feedPreviewDocument.querySelector('#feed-subtitle').textContent =
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
26 feed.subtitle;
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
27
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
28 if (typeof feed.logo !== 'undefined') {
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
29 let feedLogoTemplate =
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
30 feedPreviewDocument.querySelector('#feed-logo-template');
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
31 let logoNode = feedPreviewDocument.importNode(feedLogoTemplate.content,
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
32 true);
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
33 let imgElement = logoNode.querySelector('#feed-logo');
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
34 imgElement.setAttribute('src', feed.logo.url);
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
35 imgElement.setAttribute('alt', feed.logo.title);
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
36 feedPreviewDocument.querySelector('#feed-header').prepend(logoNode);
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
37 }
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
38
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
39 let entryTemplateElement =
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
40 feedPreviewDocument.querySelector('#entry-template');
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
41 let entryTitleTemplateElement =
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
42 feedPreviewDocument.querySelector('#entry-title-template');
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
43 let entryTitleLinkedTemplateElement =
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
44 feedPreviewDocument.querySelector('#entry-title-linked-template');
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
45 let entryFileListTemplateElement =
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
46 feedPreviewDocument.querySelector('#entry-files-list-template');
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
47 let entryFileTemplateElement =
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
48 feedPreviewDocument.querySelector('#entry-file-template');
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
49 if (feed.entries.length === 0) {
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
50 let hintTemplateElement =
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
51 previewDocument.querySelector('#no-entries-hint-template');
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
52 let hintNode = previewDocument.importNode(hintTemplateElement.content,
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
53 true);
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
54 hintNode.querySelector("#no-entries-hint").textContent =
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
55 browser.i18n.getMessage('noEntriesHint');
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
56
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
57 previewDocument.body.append(hintNode);
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
58 }
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
59 for (let entry of feed.entries) {
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
60 let entryNode =
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
61 feedPreviewDocument.importNode(entryTemplateElement.content,
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
62 true);
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
63 let titleElement;
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
64 let titleNode;
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
65
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
66 if (typeof entry.link !== 'undefined') {
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
67 titleNode = feedPreviewDocument
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
68 .importNode(entryTitleLinkedTemplateElement.content, true);
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
69 titleElement = titleNode.querySelector('.entry-link');
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
70 titleElement.href = entry.link;
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
71 titleElement.title = entry.title;
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
72 } else {
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
73 titleNode = feedPreviewDocument
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
74 .importNode(entryTitleTemplateElement.content, true);
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
75 titleElement = titleNode.querySelector('.entry-title');
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
76 }
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
77 titleElement.textContent = entry.title;
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
78 entryNode.querySelector('.entry-header').prepend(titleNode);
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
79
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
80 let timeElement = entryNode.querySelector('.entry-date > time');
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
81 timeElement.textContent = entry.date.toLocaleString();
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
82
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
83 let contentElement = entryNode.querySelector('.entry-content');
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
84 let contentDocument = new DOMParser().parseFromString(entry.content,
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
85 'text/html');
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
86 let stylesheetElement = contentDocument.createElement('link');
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
87 stylesheetElement.rel = 'stylesheet';
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
88 stylesheetElement.href =
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
89 browser.runtime.getURL('web_resources/style/entry-content.css');
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
90 contentDocument.head.appendChild(stylesheetElement);
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
91 contentElement.srcdoc = new XMLSerializer()
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
92 .serializeToString(contentDocument);
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
93 contentElement.title = entry.title;
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
94
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
95 if (entry.files.length > 0) {
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
96 let fileListNode = feedPreviewDocument
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
97 .importNode(entryFileListTemplateElement.content, true);
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
98 fileListNode.querySelector('.entry-files-title').textContent =
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
99 browser.i18n.getMessage('filesTitle');
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
100 let fileListElement =
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
101 fileListNode.querySelector('.entry-files-list');
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
102
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
103 for (let file of entry.files) {
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
104 let fileNode = feedPreviewDocument
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
105 .importNode(entryFileTemplateElement.content, true);
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
106
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
107 let fileLinkElement =
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
108 fileNode.querySelector('.entry-file-link');
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
109 fileLinkElement.href = file.url;
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
110 fileLinkElement.title = file.filename;
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
111 fileLinkElement.textContent = file.filename;
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
112
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
113 fileNode.querySelector('.entry-file-info').textContent =
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
114 `(${file.type}, ${file.size} bytes)`;
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
115
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
116 fileListElement.appendChild(fileNode);
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
117 }
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
118
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
119 entryNode.querySelector('.entry').append(fileListNode);
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
120 }
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
121
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
122 feedPreviewDocument.body.append(entryNode);
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
123 }
5d7c13e998e9 Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff changeset
124 }