readium / readium-js-viewer

👁 ReadiumJS viewer: default web app for Readium.js library
BSD 3-Clause "New" or "Revised" License
550 stars 186 forks source link

An EPUB3 With JavaScript Is Not Working Like It Does In iBooks #700

Closed dac514 closed 6 years ago

dac514 commented 6 years ago

This issue is a Bug

Expected Behaviour

When I open the test file in Readium EPUB reader for Chrome I expect javascript to generate a random poem like it does in iBooks.

Observed behaviour

The placeholder text is not replaced.

Steps to reproduce

  1. Open attached Epub3 file with Readium Chrome extension
  2. Navigate to the Poem Chapter

Test file(s)

A zip inside a zip...

Poem-1524859228._3.epub.zip

Product

danielweck commented 6 years ago

This works in the cloud reader but not in the Chrome app (explanation in a separate comment below). Here is how to test with the cloud reader:

1) Load the cloud reader URL ( https://readium.firebaseapp.com ) in web browsers (in my case: Firefox, Chrome and Safari on MacOS). 2) Drag the EPUB file from the filesystem (in my case: Finder file explorer) onto the browser window(s), and drop the EPUB file when the blurry purple border appears (same visual indicator as the Chrome app, actually). 3) Navigate to the spine item that contains the dynamic poem (i.e. last "page" of the publication). 4) Observe that the random text paragraph is present.

danielweck commented 6 years ago

The problem comes from Google's Chrome web browser, or more precisely the default CSP (Content Security Policy) of the Chrome extensions / apps framework which does not allow inline scripts, as reported in the console:

Refused to execute inline script because it violates the following Content Security Policy directive: "script-src 'self' blob: filesystem: chrome-extension-resource: 'wasm-eval'".

The solution is to move your Javascript from the body of OEBPS/chapter-001-chapter-1.xhtml into its own file (e.g. poem-script.js), and to add a link to it inside the head of the HTML document.

<script>
// <![CDATA[
function capitalizeFirstLetter( string ) {
    return string.charAt( 0 ).toUpperCase() + string.slice( 1 );
}

function poemTest() {
    var matrix = [
        [ "heartbreaking", "imploding", "wandering", "homecoming", "consuming", "vanishing", "glowering", "combusting", "concealing", "congealing" ],
        [ "pale", "bold", "cold", "wild", "white", "blue", "dead", "sad", "ripe", "slow" ],
        [ "stars", "steps", "stones", "sacs", "cells", "trucks", "homes", "trees", "debts", "tears" ],
        [ "reverberate", "reactivate", "concatenate", "initiate", "eliminate", "internalize", "communicate", "invigorate", "incinerate", "menstruate" ],
        [ "hope", "love", "fire", "shit", "fear", "waste", "shame", "light", "breath", "hate" ],
        [ "perseverance", "bulimia", "embarrassment", "metastasis", "phagocytes", "fermentations", "sociopaths", "suburbanites", "sublimation", "indifference" ],
        [ "floating", "freezing", "branding", "waking", "turning", "pissing", "grasping", "boiling", "slicing", "taking" ],
        [ "perfection", "difference", "corruption", "sollitude", "indolence", "nullity", "happiness", "ignorance", "thoughtlessness", "usefulness" ],
        [ "above", "onto", "into", "over", "against", "upon", "within", "inside", "around", "beside" ],
        [ "absence", "rigor", "vapor", "clover", "default", "Gaia", "nothing", "consent", "silence", "disgust" ],
    ];

    var poem = '';
    for ( var i = 0, len = matrix.length; i &lt; len; i++ ) {
        var min = 0;
        var max = matrix[ i ].length - 1;
        var random = Math.floor( Math.random() * (max - min + 1) ) + min;
        poem += matrix[ i ][ random ] + ' ';
    }
    var div = document.getElementById( "poemdiv" );
    div.textContent = capitalizeFirstLetter( poem ).trim() + '.';
}

window.onload = poemTest;
// ]]>
</script>
danielweck commented 6 years ago

Related issues: https://github.com/readium/readium-js-viewer/issues/615 https://github.com/readium/readium-js-viewer/issues/595 https://github.com/readium/readium-js-viewer/issues/340

danielweck commented 6 years ago

Note that the Readium Chrome app cannot enable unsafe-inline in the CSP:

Chrome extensions will let you relax the default Content Security Policy; Chrome Apps won’t.

https://developer.chrome.com/apps/contentSecurityPolicy#what