Web dev at the end of the world, from Hveragerði, Iceland

The iBooks 2.0 built-in widgets

The widgets

iBooks Author provides authors with six built-in widgets:

  1. Gallery.
  2. Media (movies and such).
  3. Review.
  4. Keynote.
  5. Interactive image.
  6. 3D.

As far as I can tell, after putting together a sample book with most of these widgets and then inspecting that book’s code in BBedit, none of these widgets use javascript in any way. I couldn’t find a single line of javascript in anywhere in the ebook’s files.

Why is this important? Because javascript is the only cross-platform and standard method for delivering interactivity in hypertext files, such as HTML or ePub. The way Apple has implemented these interactive widgets is through object tags with custom types and data attributes. The type tells iBooks what sort of widget it is and the data attributes give it the parameters. The code to do this are iBooks-only extensions to the webkit rendering engine they are using.

Here’s the full code, as far as I can tell, of a gallery widget:


<object type="application/x-ibooks+anchored" data-anchor-ref="danchor-gallery-0">
    <object type="application/x-ibooks+anchorednormal">
        <object id="gallery-0" class="s12" 
        type="application/x-ibooks+widget" 
        title="Gallery 2.1 Lorem Ipsum dolor amet, consectetur" 
        data-widget-type="gallery" 
        data-geometry="affineGeometry(440,435,1,0,0,1,291,164)" 
        data-fullscreen-only="no" 
        data-content-layout="top-bottom" 
        data-corner-radius="0.000" 
        data-content-padding="0.000" 
        data-gallery-show-thumbs="no" 
        data-gallery-share-caption="no" 
        data-stage-corner-radius="4.00000" 
        data-stage-geometry="affineGeometry(440,327,1,0,0,1,0,28)">
            <svg xmlns="http://www.w3.org/2000/svg" id="textShape-497" viewbox="0 0 440.000 38.000" preserveaspectratio="none" data-widget-object-type="caption">
                <title>
                </title>
                <desc>
                </desc>
                <rect class="s3" x="0" y="0" width="440.000" height="38.000" />
            </svg>
            <div data-widget-object-type="gallery-item" data-gallery-item-fullscreen-crop-rect="0 68 600 446">
                <img data-widget-object-type="gallery-fullscreen" src="assets/images/knights1-b.jpg" alt="" /><img data-widget-object-type="gallery-thumb" src="assets/images/ScaledThumbnail.jpg" alt="" /> 
                <div data-widget-object-type="caption">
                    <a id="textShape-499-hint" class="shape" /> 
                    <p id="textShape-499-p0" class="s13">
                        Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do tempor incididunt ut labore et dolore magna aliqua. 
                    </p>
                </div>
            </div>
            <div data-widget-object-type="gallery-item" data-gallery-item-fullscreen-crop-rect="0 307 600 446">
                <img data-widget-object-type="gallery-fullscreen" src="assets/images/knights2-b.jpg" alt="" /><img data-widget-object-type="gallery-thumb" src="assets/images/ScaledThumbnail-1.jpg" alt="" /> 
                <div data-widget-object-type="caption">
                    <a id="textShape-500-hint" class="shape" /> 
                    <p id="textShape-500-p0" class="s13">
                        Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do tempor incididunt ut labore et dolore magna aliqua. 
                    </p>
                </div>
            </div>
            <div data-widget-object-type="gallery-item" data-gallery-item-fullscreen-crop-rect="0 323 602 447">
                <img data-widget-object-type="gallery-fullscreen" src="assets/images/knights3-b.jpg" alt="" /><img data-widget-object-type="gallery-thumb" src="assets/images/ScaledThumbnail-2.jpg" alt="" /> 
                <div data-widget-object-type="caption">
                    <a id="textShape-501-hint" class="shape" /> 
                    <p id="textShape-501-p0" class="s13">
                        Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do tempor incididunt ut labore et dolore magna aliqua. 
                    </p>
                </div>
            </div>
            <div data-widget-object-type="gallery-item" data-gallery-item-fullscreen-crop-rect="0 28 605 450">
                <img data-widget-object-type="gallery-fullscreen" src="assets/images/knights4-b.jpg" alt="" /><img data-widget-object-type="gallery-thumb" src="assets/images/ScaledThumbnail-3.jpg" alt="" /> 
                <div data-widget-object-type="caption">
                    <a id="textShape-502-hint" class="shape" /> 
                    <p id="textShape-502-p0" class="s13">
                        Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do tempor incididunt ut labore et dolore magna aliqua. 
                    </p>
                </div>
            </div>
            <object type="application/x-ibooks+shape" id="textShape-498" data-widget-object-type="title">
                <svg xmlns="http://www.w3.org/2000/svg" id="textShape-498-svg" viewbox="0 0 440.000 18.000" preserveaspectratio="none">
                    <title>
                    </title>
                    <desc>
                    </desc>
                    <rect class="s3" x="0" y="0" width="440.000" height="18.000" />
                </svg>
                <div class="s4" id="textShape-498-div">
                    <a id="textShape-498-hint" class="shape" /> 
                    <p id="textShape-498-p0" class="s14">
                        <a id="anchor-1" />
                        <span class="c7">
                            Gallery 2.1
                        </span>
                        <span class="c6">
                            Lorem Ipsum dolor amet, consectetur
                        </span>
                    </p>
                </div>
            </object>
            <img id="gallery-0-alt" src="assets/images/gallery_74D001F0-1189-45F5-A788-7BF5204EF72E_fallback.png" alt="Gallery 2.1 Lorem Ipsum dolor amet, consectetur" /> 
        </object>
    </object>
    <object type="application/x-ibooks+anchoredgutter" data-geometry="affineGeometry(125,158.897705,1,0,0,1,50,0)" data-gutter-order="0" class="s15">
        <div data-widget-object-type="style-info" data-widget-style-type="paragraph-style" class="s16" /> <img id="gallery-0-gutter" class="s3" src="assets/images/flow.png" alt="" /> 
    </object>
</object>
<svg xmlns="http://www.w3.org/2000/svg" id="textShape-106" viewbox="0 0 962.000 686.000" preserveaspectratio="none">
    <title>
    </title>
    <desc>
    </desc>
    <rect class="s2" x="0" y="0" width="962.000" height="686.000" />
</svg>
<svg xmlns="http://www.w3.org/2000/svg" id="textShape-107" viewbox="0 0 962.177 0.024" preserveaspectratio="none">
    <title>
    </title>
    <desc>
    </desc>
    <path class="s6" d="M 0 0.024394 L 962.176758 0" />
</svg>
<svg xmlns="http://www.w3.org/2000/svg" id="textShape-108" viewbox="0 0 0.000 620.000" preserveaspectratio="none">
    <title>
    </title>
    <desc>
    </desc>
    <path class="s11" d="M 0 620 L 0.000022 0" />
</svg>
<object type="application/x-ibooks+shape" id="textShape-109" data-original-id="textShape-104">
    <svg xmlns="http://www.w3.org/2000/svg" id="textShape-109-svg" viewbox="0 0 924.000 20.000" preserveaspectratio="none">
        <title>
        </title>
        <desc>
        </desc>
        <rect class="s3" x="0" y="0" width="924.000" height="20.000" />
    </svg>
    <div class="s4" id="textShape-109-div">
        <a id="textShape-109-hint" data-original-id="textShape-104-hint" class="shape" /> 
        <p id="textShape-109-p0" class="s9">
            <span class="c6">
                8
            </span>
        </p>
    </div>
</object>

In theory, other reading systems could reverse-engineer the code for this, or a conversion tool could be built that provides javascript that renders this, but that task is enormous given the undocumented complexity of the parameters possible and the variety of features these widgets support.

The problem

The biggest disappointment with the iBooks 2.0 textbook format isn’t that Apple decided to extend ePub. They have done so before. Fixed-layout ePubs, because it was a fairly well documented extension (even though that documentation wasn’t public) and conceptually straightforward, ended up being a positive innovation for the ebook industry.

The biggest, most heart-wrenching, disappointment is that Apple could have done all of this in a standards-friendly manner.

Instead of using an undocumented extensions to CSS, they could have built on the proposed standards for regions and text-wrapping.

The solution they chose for widgets is also perplexing since ePub3 provides a solution exactly for this use case: Bindings.

ePub3 provides a standard method for defining handlers for media types it doesn’t support. Through the bindings element Apple could have provided handlers for its widgets, written in javascript, so that its books would have been forward compatible with other, future, ePub3 reading systems.

The widget problem can be solved either by conversion tools or by competing reading systems by reverse engineering the data attributes and object types Apple uses, and writing compatible handlers.

But I don’t see an easy way to convert the layout code to more standard CSS. The basic model behind Apple’s method and the methods proposed by the CSS WG differ in fairly fundamental ways.

I hope I’m wrong.


Update: iBooks widgets – to javascript or not to javascript. Again, I do not lament the fact that these widgets weren't implemented in javascript.

You can also find me on Mastodon and Twitter