readium / readium-js-viewer

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

navigator.epubReadingSystem injected in EPUB content documents with delay #13

Closed codingisacopingstrategy closed 10 years ago

codingisacopingstrategy commented 10 years ago

An XHTML spine document with the following body:

<body>
    <script type="text/javascript">
        alert("Hello, my dear friends, my name is" + navigator.epubReadingSystem.name);
    </script>
    <section>FOO BAR</section>
</body>

Will have an alert pop up in the Readium Chrome extension, whereas in the readium-js viewer we get an error:

Uncaught TypeError: Cannot read property 'name' of undefined

screenshot from 2013-11-30 18 47 52

danielweck commented 10 years ago

Have you tried to query the epubReadingSystem object after body.onload or document.readystate/dom.loaded? (from the top of my head) dan

On Saturday, November 30, 2013, Eric Schrijver wrote:

An XHTML spine document with the following body:

FOO BAR

Will have an alert pop up in the Readium Chrome extension, whereas in the readium-js viewer we get an error:

Uncaught TypeError: Cannot read property 'name' of undefined

[image: screenshot from 2013-11-30 18 47 52]https://f.cloud.github.com/assets/56819/1649171/9e14130a-59e7-11e3-9c1d-00320e80a1ed.png

— Reply to this email directly or view it on GitHubhttps://github.com/readium/readium-js-viewer/issues/13 .

codingisacopingstrategy commented 10 years ago

Hello Daniel, Thanks for your reaction and suggestion.

I’ve now tried both body onload="function()" and document.addEventListener( "DOMContentLoaded", function, false )

The problem then might be with require.js: because its asynchronous, Readium won’t necessarily be loaded when the book’s JavaScript loads. I’ll try and see if I can get the synchronous version to work.

codingisacopingstrategy commented 10 years ago

14

danielweck commented 10 years ago

The epubReadingSystem object is "injected" into the iframe's window.navigator after the DOM content document is loaded (iframe.onload event). See:

https://github.com/readium/readium-shared-js/blob/develop/js/views/iframe_loader.js

codingisacopingstrategy commented 10 years ago

Thanks for the pointer. So how could I make sure epubReadingSystem loaded before I call it?

danielweck commented 10 years ago

I've used a combination of tricks in my EPUB3 experiments to detect reading systems (iBooks-iOS, iBooks-MacOSX, Kobo, Readium-Chrome, Readium-JS, Azardi, GooglePlay, etc.) ... just like browser "sniffing", sigh :( I have not been playing with ReadiumJS that much, but I think I used something along the lines of: onDocumentLoaded + setTimeout(). Dan

On Tue, Dec 3, 2013 at 10:57 AM, Eric Schrijver notifications@github.comwrote:

Thanks for the pointer. So how could I make sure epubReadingSystem loaded before I call it?

— Reply to this email directly or view it on GitHubhttps://github.com/readium/readium-js-viewer/issues/13#issuecomment-29700316 .

bormind commented 10 years ago

There is an event ReadiumSDK.Events.READER_INITIALIZED that is fired when reader is initialized.

danielweck commented 10 years ago

Thanks Boris, this is a useful event to know about from the perspective of an app developer. However, the problem at hand here is that content authors need to be able to access the ePubReadingSystem object from Javascript code contained within XHTML5 spine items, in a platform-agnostic way (i.e. not by hooking into Readium-specific events or objects). The ePubReadingSystem API is useful for content authors who need to determine Reading System capabilities, or simply to detect that a given HTML page is being rendered in the context of a Reading System (rather than within a regular web browser). Daniel

bormind commented 10 years ago

Daniel, I the context of specific content document the reader fires ReadiumSDK.Events.CONTENT_DOCUMENT_LOADED event and passes out to subscriber the $ifram object and spineItem object.

danielweck commented 10 years ago

@bormind Oh yes, sure. However, content authors should never have to hook into the internals of Reading Systems (Readium, iBooks, Kobo, etc.). The purpose of the lightweight ePubReadingSystem API is to expose a common set of platform-agnostic EPUB3 properties (RS capabilities, version, etc.). So hooking into ReadiumSDK.Events would somewhat defy the point.

bormind commented 10 years ago

Daniel, I did some reading on ePubReadingSystem and now I understand it a little bit better. And I think we have a bigger problem - the ePubReadingSystem is relevant not only for browser based but for any reading system. and we should move the ePubReadingSystem object initialization to the shared-js. This will resolve the current issue with initialization too.

danielweck commented 10 years ago

@bormind it's already in shared-js, but the object gets injected on the iframe.onload event...which is after dom-ready / document loaded, I think.

https://github.com/readium/readium-shared-js/blob/develop/js/views/iframe_loader.js

bormind commented 10 years ago

Yes, I know. But this is wrong. We create ePubReadingSystem in readium.js and store it in navigation object. Then we inject it to the iframe's child window when iframe's content is rendered. This creates reverse dependency and require duplication of ePubReadingSystem creation in other reading systems (Launchers).

danielweck commented 10 years ago

@bormind in Readium-Chrome, ePubReadingSystem.js used to define the object instance once, this JS file was then boostrapped via reader.html (or other "require" mechanism), then the object got injected into loading iframe. Note that because the ePubReadingSystem object contains an app-specific name + version number, it needs to be updated/intercepted by the application before it gets used inside iframes by content documents (spine items or out-of-spine XHTML).

codingisacopingstrategy commented 10 years ago

Hello Daniel and Boris,

Thanks for your comments.

content authors need to be able to access the ePubReadingSystem object from Javascript code contained within XHTML5 spine items, in a platform-agnostic way (i.e. not by hooking into Readium-specific events or objects)

Indeed, that would be great! (Though making ePubs feels a bit like the days of the old days of HTML, it would be great if we could get by without reader sniffing).

I’m not sure, by the way, that the epubReadingSystem gets correctly inserted into the iFrame in Readium.js—it appears to be present in the host frame rather than the iFrame:

Readium Chrome:

> navigator.epubReadingSystem undefined > document.getElementsByTagName('iframe')[0].contentWindow.navigator.epubReadingSystem Object {name: "Readium", version: "0.9.1", layoutStyle: "paginated", hasFeature: function}

Readium.js Viewer:

> navigator.epubReadingSystem Object {name: "Readium.js", version: "0.0.1", layoutStyle: "paginated", hasFeature: function} > document.getElementsByTagName('iframe')[0].contentWindow.navigator.epubReadingSystem undefined

But I guess I should switch to the devel branch to really follow what’s going on?

Cheers,

danielweck commented 10 years ago

develop branch, yes.

bormind commented 10 years ago

Eric, for sure the develop branch is the one to use. Please clone readium-js-viewer recursively to correctly pull all the dependencies (sub-projects). Now, the epubReadingSystem is not yet fixed in develop branch. It will be in the few days. We have a code freeze for develop branch right now. The fix will remove the ePubReadingSystem definition from readium.js - it doesn't belong there. Instead default ePubReadingSystem will be set in readium-shared-js. But reading system should override the defaults with appropriate settings. The right place to do this is in the subscription to ReadiumSDK.Events.READER_INITIALIZED event. Example will be provided in readium-js-viewer.

danielweck commented 10 years ago

Boris, let's make sure that with this approach the ePubReadingSystem object is ready in time for when a spine item / XHTML content document's Javascript actually needs to access it, i.e. usually when the window.onload / DOM.ready events are triggered inside the iframe host. Remember, the ePubReadingSystem object needs to be explicitely injected into the navigator for each iframe's internal window, as soon as possible. Is there a better alternative than iframe.onload? Daniel

On Monday, December 9, 2013, Boris Schneiderman wrote:

Eric, for sure the develop branch is the one to use. Please clone readium-js-viewer recursively to correctly pull all the dependencies (sub-projects). Now, the epubReadingSystem is not yet fixed in develop branch. It will be in the few days. We have a code freeze for develop branch right now. The fix will remove the ePubReadingSystem definition from readium.js - it doesn't belong there. Instead default ePubReadingSystem will be set in readium-shared-js. But reading system should override the defaults with appropriate settings. The right place to do this is in the subscription to ReadiumSDK.Events.READER_INITIALIZED event. Example will be provided in readium-js-viewer.

— Reply to this email directly or view it on GitHubhttps://github.com/readium/readium-js-viewer/issues/13#issuecomment-30151477 .

bormind commented 10 years ago

Daniel, you are absolutely right - I think there is a better way to set ePubReadingSystem than using ifrme's onload. Because READER_INITIALIZED is triggered before iframes are created (they are created on opening spine items). If reading system will use reader's READER_INITIALIZED event to set ePubReadingSystem (or with defaults set in readium-shared-js) we will be able to pass the ePubReadingSystem to iframe's window.navigation. when iframe is just created and not when iframe is loaded with the document.

Boris.

danielweck commented 10 years ago

Issue moved here:

https://github.com/readium/readium-shared-js/issues/41