view js/feed-preview.js @ 26:f0c4a458869c

Open links within feed content in a new tab Open links within feed content in a new non-sandboxed tab rather than in the sandboxed iframe itself.
author Guido Berhoerster <guido+feed-preview@berhoerster.name>
date Wed, 02 Jan 2019 21:53:37 +0100
parents ff5e5e3eba32
children 688d75e554e0
line wrap: on
line source

/*
 * Copyright (C) 2018 Guido Berhoerster <guido+feed-preview@berhoerster.name>
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

'use strict';

export function renderFeedPreview(feedPreviewDocument, feed) {
    // inject XSL stylesheet which transforms XHTML to HTML allowing the use of
    // the HTML DOM
    let xslFilename = browser.runtime.getURL('web_resources/xhtml-to-html.xsl');
    let xmlStylesheetNode =
            feedPreviewDocument.createProcessingInstruction('xml-stylesheet',
            `type="application/xslt+xml" href="${xslFilename}"`);
    feedPreviewDocument.firstChild.after(xmlStylesheetNode);

    feedPreviewDocument.querySelector('#default-stylesheet').href =
            browser.runtime.getURL('web_resources/style/feed-preview.css');

    feedPreviewDocument.querySelector('title').textContent = feed.title;

    feedPreviewDocument.querySelector('label[for="feed-reader-selection"]')
            .textContent = browser.i18n.getMessage('feedReaderSelectionLabel');
    feedPreviewDocument.querySelector('[name="subscribe"]').textContent =
            browser.i18n.getMessage('subscribeButtonLabel');

    feedPreviewDocument.querySelector('#feed-title').textContent = feed.title;
    feedPreviewDocument.querySelector('#feed-subtitle').textContent =
            feed.subtitle;

    if (typeof feed.logo !== 'undefined') {
        let feedLogoTemplate =
                feedPreviewDocument.querySelector('#feed-logo-template');
        let logoNode = feedPreviewDocument.importNode(feedLogoTemplate.content,
                true);
        let imgElement = logoNode.querySelector('#feed-logo');
        imgElement.setAttribute('src', feed.logo.url);
        imgElement.setAttribute('alt', feed.logo.title);
        feedPreviewDocument.querySelector('#feed-header').prepend(logoNode);
    }

    feedPreviewDocument.querySelector("#no-entries-hint").textContent =
            browser.i18n.getMessage('noEntriesHint');

    let entryTemplateElement =
            feedPreviewDocument.querySelector('#entry-template');
    let entryTitleTemplateElement =
            feedPreviewDocument.querySelector('#entry-title-template');
    let entryTitleLinkedTemplateElement =
            feedPreviewDocument.querySelector('#entry-title-linked-template');
    let entryFileListTemplateElement =
            feedPreviewDocument.querySelector('#entry-files-list-template');
    let entryFileTemplateElement =
            feedPreviewDocument.querySelector('#entry-file-template');
    for (let entry of feed.entries) {
        let entryNode =
                feedPreviewDocument.importNode(entryTemplateElement.content,
                true);
        let titleElement;
        let titleNode;

        if (typeof entry.link !== 'undefined') {
            titleNode = feedPreviewDocument
                    .importNode(entryTitleLinkedTemplateElement.content, true);
            titleElement = titleNode.querySelector('.entry-link');
            titleElement.href = entry.link;
            titleElement.title = entry.title;
        } else {
            titleNode = feedPreviewDocument
                    .importNode(entryTitleTemplateElement.content, true);
            titleElement = titleNode.querySelector('.entry-title');
        }
        titleElement.textContent = entry.title;
        entryNode.querySelector('.entry-header').prepend(titleNode);

        let timeElement = entryNode.querySelector('.entry-date > time');
        timeElement.textContent = entry.date.toLocaleString();

        let contentElement = entryNode.querySelector('.entry-content');
        let contentDocument = new DOMParser().parseFromString(entry.content,
                'text/html');
        let stylesheetElement = contentDocument.createElement('link');
        stylesheetElement.rel = 'stylesheet';
        stylesheetElement.href =
                browser.runtime.getURL('web_resources/style/entry-content.css');
        contentDocument.head.appendChild(stylesheetElement);
        // open links in a new tab rather than within the iframe
        for (let linkElement of contentDocument.links) {
            linkElement.target = '_blank';
        }
        contentElement.srcdoc = new XMLSerializer()
                .serializeToString(contentDocument);
        contentElement.title = entry.title;

        if (entry.files.length > 0) {
            let fileListNode = feedPreviewDocument
                    .importNode(entryFileListTemplateElement.content, true);
            fileListNode.querySelector('.entry-files-title').textContent =
                    browser.i18n.getMessage('filesTitle');
            let fileListElement =
                    fileListNode.querySelector('.entry-files-list');

            for (let file of entry.files) {
                let fileNode = feedPreviewDocument
                        .importNode(entryFileTemplateElement.content, true);

                let fileLinkElement =
                        fileNode.querySelector('.entry-file-link');
                fileLinkElement.href = file.url;
                fileLinkElement.title = file.filename;
                fileLinkElement.textContent = file.filename;

                fileNode.querySelector('.entry-file-info').textContent =
                        `(${file.type}, ${file.size} bytes)`;

                fileListElement.appendChild(fileNode);
            }

            entryNode.querySelector('.entry').append(fileListNode);
        }

        feedPreviewDocument.body.append(entryNode);
    }
}