view js/feed-preview.js @ 57:3c97046c2348

Fix non-responsive buttons for managing feed readers In recent Firefox releases the "explicitOriginalTarget" property returns the associated form element instead of the originally clicked button so that the buttons for managing feed readers on the option page no longer worked. Determine the button used to submit the form using the "submitter" property of the new SubmitEvent instead. Add a polyfill for older Firefox releases not yet supporting this.
author Guido Berhoerster <guido+feed-preview@berhoerster.name>
date Wed, 06 May 2020 13:42:35 +0200
parents 4492db3b277e
children
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';

function formatFileSize(size) {
    const LIMITS_UNITS = new Map([
        [1024 * 1024 * 1024, 'GiB'],
        [1024 * 1024, 'MiB'],
        [1024, 'KiB'],
        [0, 'B']
    ])
    for (let [limit, unit] of LIMITS_UNITS) {
        if (size >= limit) {
            return `${Number(size / limit).toFixed(1)} ${unit}`;
        }
    }
    return '? B';
}

export function renderFeedPreview(feedPreviewDocument, feed,
        expandEntriesByDefault) {
    // 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');

    // link to the currently viewed feed in order to allow feed reader addons
    // to subscribe to it
    let feedLinkElement = feedPreviewDocument.querySelector('#feed-link');
    feedLinkElement.href = feed.url;
    feedLinkElement.type = feed.type;

    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);
        entryNode.querySelector('details.entry').open = expandEntriesByDefault;

        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}, ${ formatFileSize(file.size)})`;

                fileListElement.appendChild(fileNode);
            }

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

        feedPreviewDocument.body.append(entryNode);
    }
}