EPUB Scriptable Components provides an interoperable publish and subscribe (pubsub) pattern by which interactive content can be created and incorporated into EPUB Publications.

The third bullet in s. 2.2 indicates how reading systems handle the situations where they don't support spine-level scripting but are ESC-aware and do support spine-level scripting but aren't ESC-aware. A third case has been identified where the reading system supports spine-level scripting and is also ESC-aware. It is not clear what the expectations are in this case, as further study is needed in real-world systems. Further guidance may be added in a future draft.

Overview

Purpose and Scope

This specification, EPUB Scriptable Components, provides an interoperable publish and subscribe (pubsub) pattern by which interactive content can be created and incorporated into EPUB Publications. This interactive content can be rendered in any Reading System that conforms to the requirements in this specification.

This specification is not a replacement for the scripting architecture defined in [[ContentDocs301]], and implementing or using the APIs and processes does not replace the requirements, restrictions and best practices defined in that specification.

Scriptable Components can be used in Reading Systems that support only container-constrained scripts or that support full spine-level scripting.

Security

The goal of this specification and [[ScriptableComponents-Packaging]] is to allow third-party Scriptable Components (widgets) to be securely integrated into XHTML Content Documents. As such, this specification requires that Scriptable Components be embedded using the [[HTML5]] iframe element ‒ whether they are embedded into an XHTML Content Document in an EPUB Publication or into another Scriptable Component.

This specification assumes that domain isolation exists between the Scriptable Components, but the Reading System might or might not enforce domain isolation on the document referenced by the iframe element. If domain isolation is enforced a relatively high degree of isolation and security is achieved. If domain isolation is not enforced security could be an issue (e.g., the Scriptable Component might compromise the EPUB Publication and/or the Reading System).

Compliance with this specification does not guarantee any particular level of security, it is intended to provide a framework in which Reading System implementors can achieve security with third-party scripting.

User Agent to Reading System Communication 

Some Reading Systems on mobile devices are implemented using a system-provided web component (often referred to as a WebView) for the rendering of content. It is common for these components to provide some level of communication with the rest of the Reading System, for instance to report on progress and load content. Such calls can have both security and privacy implications. For example, it might be possible to determine the name of the user and the list of books in the users library. Such communications can also be used to exploit vulnerabilities, like buffer overflows, in the Reading System.

This specification does not directly resolve these issues. It is the responsibility of the Reading System implementor to account for the security and privacy implication of WebView-to-application communication.

Privacy

As Scriptable Components evolve, they will invariably make use of communication resources to retrieve and store remote (cloud) data ‒ data that might contain sensitive personal information.

It is beyond the scope of this specification to ensure or enforce the privacy of this information. Reading Systems might employ measures to restrict or eliminate communication across a network, or limit or disallow cookies and local storage.

Terminology

Refer to the EPUB Specifications for definitions of EPUB-specific terminology used in this document.

Component Parent

The parent that hosts the Scriptable Component, which could be either:

  1. another Scriptable Component, if referenced from an [[!HTML5]] iframe within it; or
  2. the Reading System, if referenced from an iframe in a Top-level Content Document.
PubSub Communication Bridge

The publisher/subscriber relationship defined in 4.2.1 The PubSub Communication Bridge to facilitate message communication.

Scriptable Component

A scripted Distributable Object that is distributed for use in other EPUB Publications. A Scriptable Component conforms to all content requirements in this specification and in [[!ScriptableComponents-Packaging]].

Conformance

Content Conformance

An EPUB Content Document that supports Scriptable Components MUST meet the following criteria:

An EPUB Publication that contains EPUB Scriptable Components MUST be packaged in conformance with [[!ScriptableComponents-Packaging]].

Reading System Conformance

EPUB Reading Systems that support Scriptable Components MUST meet the following criteria:

Scriptable Components

Integration

All Scriptable Components MUST be hosted in an [[!HTML5]] iframe element.

All resources used by a Scriptable Component MUST be included in the EPUB Container, unless allowed to be remotely hosted (e.g., audio/video).

Security

Scriptable Components MUST assume that they exist in a separate domain from the EPUB Content Document that hosts them. Reading Systems MAY enforce domain isolation of Scriptable Components.

The only means of communication between an EPUB Content Document and the contained Scriptable Components MUST occur using the EPUB Scriptable Components protocol. No direct access across Scriptable Component boundaries is allowed; properties contained on window.parent [[!HTML5]] MUST NOT be accessed.

Inter-Component Communication

Introduction

A Scriptable Component communicates via a protocol layer driven internally by an implementation of the HTML5 postMessage API [[WebMessaging]].

The Scriptable Component functions ubiquitously by being both subscriber and subscribed in this model. This distributed model means that each Scriptable Component is responsible for relaying the messaging protocol to its direct dependent children and its parent in turn.

This protocol defines the methods by which Scriptable Components communicate, and predefines a set of message topics for communication.

PubSub Protocol

The PubSub Communication Bridge

The window.postMessage() API [[!WebMessaging]] provides a safe communication bridge between two Scriptable Components in different domains, and is used by Scriptable Components to publish messages to target windows – their subscribers.

Scriptable Components MUST use the window.postMessage() method [[!WebMessaging]] to publish messages to, and through, target windows ‒ referred to hereafter as the PubSub Communication Bridge.

Subscribers, in turn, MUST register event listeners on the event handler event type "message" [[!WebMessaging]] to subscribe to messages.

Message Structure

Scriptable Components publish messages over the PubSub Communication Bridge to relay topics and events as they occur or are passed through.

Each message MUST be serialized as a JSON object [[!RFC4627]] that conforms to the schema in Appendix A.

Messages are composed of the following properties:

  • componentId — The REQUIRED componentId property contains a string identifier that uniquely identifies a Scriptable Component for the lifetime of the session (e.g., a GUID [[RFC4122]]). See also Appendix B for examples.
  • messageId — The REQUIRED messageId property contains a string identifier that uniquely identifies a message. This specification does not require a format for the identifier. The identifier can be a combination of a unique value with the Scriptable Component identifier, a simple monotonic counter value or any other value guaranteed to be unique.
  • timestamp — The REQUIRED timestamp property identifies the time the message was generated. The value MUST be the value returned from the JavaScript Date.now() function, as implemented by the Reading System.
  • type — The REQUIRED type property identifies that the object represents a message generated by a Scriptable Component. The value MUST be the string "epubsc_message".
  • method — The REQUIRED method property contains a string identifier that declares the event method being invoked. The value MUST be one of the following: "epubsc_subscribe", "epubsc_unsubscribe" or "epubsc_publish".
  • topic — The REQUIRED topic property identifies the name of the channel the message is being published to. The value MUST be a topic name, as defined in 4.4.2 Topic Names and 4.4.3 Reserved Topic Names.
  • topicData — The OPTIONAL topicData property is included in a message when the topic requires additional data. If present, the value MUST be a JSON object [[!RFC4627]].

Timing

Due to the distributed nature of the protocol defined in this section, the order in which messages are received by a subscriber cannot be guaranteed.

Scriptable Components consequently SHOULD NOT be designed to be dependent on an orderly arrival of messages from separate components. Scriptable Components SHOULD rely on the ordering of messages from a unique instance of a component. Message timing information SHOULD be extracted from the timestamp property.

Methods

Implementation

Scriptable Components MUST implement the methods defined in this section to facilitate communication over the PubSub Communication Bridge.

Subscribe ("epubsc_subscribe")

The epubsc_subscribe method provides the mechanism for a Scriptable Component to subscribe to a topic.

This method needs to be aware of the topic to begin listening.

Unsubscribe ("epubsc_unsubscribe")

The epubsc_unsubscribe method provides the mechanism for a Scriptable Component to terminate listening to a particular topic.

This method needs to be aware of the topic string value to facilitate this lookup and removal.

Publish ("epubsc_publish")

The epubsc_publish method allows a ready Scriptable Component to publish a message on a previously subscribed topic.

This method needs to be aware of the topic name, and the message object to be passed.

Topics

Communication

All topic subscriptions and publications MUST be propagated up to the Component Parent, regardless of subscription

The component MUST send published topics to all subscribed children. If the sender is also subscribed, it MUST also receive the topic.

A component MAY subscribe to a topic multiple times.

A component MAY unsubscribe from a topic by removing a specific handler.

Topic Names

Topic names are used to identify what data is carried by a specific publish request.

Topic names MUST start with an alphanumeric character and MUST NOT contain whitespace characters, which are defined as the following:

  • CHARACTER TABULATION (U+0009)
  • LINE FEED (U+000A)
  • FORM FEED (U+000C)
  • CARRIAGE RETURN (U+000D)
  • SPACE (U+0020)

Implementations can define their own topic names, but such names MUST NOT begin with the text "epubsc", as this prefix is reserved for topics defined by this specification. The colon character (":", U+003A) is reserved by this specification for future use and MUST NOT be used in custom topic names. However, the inclusion of the character MUST NOT be considered an error by Reading Systems implementing this version of the specification.

Other than the reserved names, this specification does not define the meaning of any topic names.

Reserved Topic Names

Ready ("epubsc_ready")

The topic "epubsc_ready" is reserved to indicate that a component has entered its ready state and is able to receive messages.

At startup, a Scriptable Component MUST announce that it is ready to handle messages (topic subscriptions and publications) by publishing a message with the epubsc_ready topic.

The Scriptable Component also has to be able to store and maintain a list of participating Scriptable Components using their Component IDs.

Pause ("epubsc_pause")

The topic "epubsc_pause" is reserved to indicate that a component should enter its paused state (e.g., when it is no longer on a visible page or when the reading system is not the frontmost application).

Resume ("epubsc_resume")

The topic "epubsc_resume" is reserved to indicate that a component should resume its ready state.

Load ("epubsc_load")

The topic "epubsc_load" is reserved to indicate that a component has begun loading.

Unload ("epubsc_unload")

The topic "epubsc_unload" is reserved to indicate that a component has begun unloading.

Event ("epubsc_event")

The topic "epubsc_event" is reserved for JavaScript event communication.

Initialization

To prepare to send and receive messages, a Scriptable Component MUST initiate the following steps during its load process:

  1. It MUST set up the PubSub Communication Bridge, which requires that:

    1. All Scriptable Component's MUST be able to publish messages on the PubSub Communication Bridge.
    2. Scriptable Components that contain child components, or need to communicate on the PubSub Communication Bridge, MUST be able to subscribe to messages.

    This PubSub Communication Bridge is used to pass a message of a specific method type, as defined in 4.2.2 Message Structure.

    The methods used to communicate are described in 4.3 Methods. These methods define a communication channel for specific handling.

  2. After completing any other custom steps in its load process, it MUST publish an "epubsc_ready" topic to announce to all subscribers that it is now active (refer to 4.4.1 Communication for more information). At the same time, the Component MAY subscribe to its own "epubsc_ready" topic if it needs to receive its own updates.

At this stage, the Component can subscribe, unsubscribe, publish, and send topics through the PubSub Communication Bridge.

Component-Parent Event Communication

Introduction

Scriptable Components can receive JavaScript events that are both meaningful and meaningless to their operation.

For example, a key press in an input field of the Scriptable Component would typically need to be handled by the Component, but a right arrow key press might not. Whether the Scriptable Component transmits information about the event to its Parent Component, giving the parent an opportunity to respond to it, depends on the nature of the event.

This section defines how Scriptable Components publish these events to their parent(s),  including whether they were or were not handled.

Handling and Propagating Events

Scriptable Components MUST relay [[!UIEvents]] events to their Parent Component via the PubSub Communication Bridge.

Communication of these events is REQUIRED whether the event has been handled by the Scriptable Component or not, and the message MUST use the epubsc_publish method with the reserved topic "epubsc_event"

To indicate if the event has been handled, the message's topicData MUST include the boolean property handled. The Component Parent SHOULD NOT respond to the event if this property is true.

The topicData also MUST be populated with copies of all applicable attributes [[!UIEvents]] from the original event (e.g., altKey, button, ctrlKey, type).

All event messages MUST be propagated up to the Component Parent; the component MUST NOT send event messages to any of its children.

Message Schema

The JSON representation schema for messages:

{
   "id": "http://www.idpf.org/epub/sc/1.0/schema.json",
   "$schema": "http://json-schema.org/draft-04/schema#",
   "type": "object",
   "title": "EPUB Scriptable Components Message Schema",
   "description": "Schema validation for the message body",
   "properties": {
      "componentId": { "type": "string" },
      "messageId": { "type": "string" },
      "timestamp": { "type": "number" },
      "type": {
         "type": "string",
         "enum": ["epubsc_message"]
      },
      "method": {
         "type": "string",
         "enum": ["epubsc_subscribe", "epubsc_unsubscribe", "epubsc_publish"]
      },
      "topic": { "type": "string" },
      "topicData": { "type": "object" }
   },
   "required": ["componentId", "messageId", "timestamp", "method", "topic"],
   "additionalProperties": false
}

Validation using this schema requires a processor that supports [[!JSON-Schema]].

ComponentID sample code

The uniqueness of a component ID over a session is critically important to correct behavior of Scriptable Components. An implementation of [[RFC4122]] provides sufficient uniqueness.

Examples include:

See http://stackoverflow.com/questions/105034/create-guid-uuid-in-javascript for other examples and further discussion.

Example use cases

Allow two Scriptable Components to communicate. A UI control in one component may direct a visualization change in a second component.

An embedded Scriptable Component may contain a running video. When the EPUB document is paged or scrolled the Reading System will instruct the Scriptable Component to pause the video.

UI events occurring in IFrames are not bubbled to parent windows. Scriptable Components will enable event propagation and handling by parent windows and Reading Systems.

Acknowledgements and Contributors

EPUB has been developed by the International Digital Publishing Forum in a cooperative effort, bringing together publishers, vendors, software developers, and experts in the relevant standards.

The EPUB Scriptable Components Packaging and Integration 1.0 specification was prepared by the International Digital Publishing Forum's EPUB Working Group, operating under under the leadership of:

Active members of the working group at the time of publication were:

IDPF Members

Invited Experts/Observers