Introduction Versioning Hello World Events Declaration Type Context Propagation Navigation Spatial Explicit Global Screen Standard Group Templates Text Mosaic Video API itv.version itv.log itv.setKeys itv.getFocus itv.setFocus itv.getIndex itv.setIndex itv.getFocusedIndex itv.getState itv.setState itv.update itv.processEvent itv.getStyle itv.setStyle itv.addStyleValues itv.getPos itv.hasClass itv.addClass itv.removeClass itv.replaceClass

iTV.js Framework - Documentation

Introduction

Designing a TV interface is a little different to designing one for other types of platforms. The most obvious difference between a TV and a standard desktop or tablet/smartphone interface is the lack of a pointing device. Indeed, instead of using a mouse or touch screen, the user's only tool to navigate through the interface is a remote control. This difference entails a certain way of presenting information to the user and also how he may interact with it. This framework has been designed with this in mind.

The aim of this framework is to facilitate the creation of applications destined to run on browser based television interfaces. It adds functionality to an ordinary HTML document in ways that are specifically well suited to television interface requirements. A key aspect that makes this framework easy to use is that it doesn't assume you are running a particular flavor of browser with a specific feature set. Instead, it uses standard HTML and performs feature detection in order to perform specific HbbTV functionality if necessary. This means you can develop in the comfort of your desktop browser with all the debugging tools available (ex: Chrome DevTools, Firefox Firebug or Edge Developer Tools) and deploy the exact same code to your TV/STB.

This documentation assumes you have basic knowledge of HTML/CSS/JavaScript and will guide you through the functionalities of this framework in order to help you become a proficient interactive television web application developer.

Versioning

This framework follows the Semantic Versioning (SemVer) guidelines. The rules are pretty simple, given a version number MAJOR.MINOR.PATCH, increment the:

  1. MAJOR version when you make incompatible API changes,
  2. MINOR version when you add functionality in a backwards-compatible manner, and
  3. PATCH version when you make backwards-compatible bug fixes.

This means that the user of this framework can upgrade to a newer version without worrying about compatibility as long as the MAJOR version number isn't incremented. If it is, a migration guideline will be made available in order to make the upgrade process as smooth and painless as possible.

Hello World

The simplest application you may write is as follows:

<!DOCTYPE html>
<html>
	<head>
		<script type="text/javascript" src="itv.js"></script>
	</head>
	<body>
		<h1>Hello World</h1>
	</body>
</html>

In this basic HTML page, the simple fact of including the iTV.js framework means that this is now a valid HbbTV application. Indeed, the framework checks to see if the browser is HbbTV compliant and if it is, adds the necessary <object> in order to run the OIPF plug-in to set the page visibility.

During the course of this documentation, we will take this simple example and add functionality concentrating on what is inside the <body> element.

Events

An essential part of creating a user interface is to perform actions when a specific event occurs. These events can be user generated (remote control key presses) or internal to the application (page loaded, index changed, video reached the end, etc.). That is why the framework enables you to easily perform actions associated with an event.

Events - Declaration

Inside an HTML element, you may associate an action with an event by creating an attribute that consists of the event name prefixed by "itv-event-". Then, you set the value of this attribute with whatever JavaScript you wish to perform when this event occurs.

Here is an Example:

<body itv-event-load="itv.log('Hello World')"></body>

The event "load" occurs when the HTML document is ready for you to interact with. This is most often the entry point of the application. When this event is triggered, it calls whatever JavaScript is associated with it. Here, it will call itv.log("Hello World") that will display the string "Hello World" on screen.

Events - Type

There are two types of events:

  1. User generated events which are triggered when the user presses a remote control key. These events are triggered on the element that is currently focused.
  2. Internally generated events such as the load event we have seen previously. The other internally generated events will be mentioned later on in order to better explain the context in which they occur.

Note: According to the HbbTV spec, you must explicitly request the capture of specific keys. This is done by calling itv.setKeys(mask) where mask is a combination of values that correspond to sets of keys.

Key Masks:

TypeKeysMask
Colorred0x1
Colorgreen0x2
Coloryellow0x4
Colorblue0x8
Navigationleft, up, right, down, enter, back0x10
VCRplay, pause, stop, next, prev, fast_fwd, rewind, play_pause0x20
Scrollpage_up, page_down0x40
Infoinfo0x80
Numeric[0..9]0x100
Alpha[a..z]0x200
Othersubtitle0x400

It is good practice to always set the key mask you wish to use just in case; non-HbbTV browsers are not affected by this in any way.

When running an app on a PC browser, you will find that most remote control keys have a direct keyboard counterpart. Those include navigational, numeric, alpha and scroll keys. For the rest, the following shortcuts are available:

Remote control keyKeyboard shortcut
redShift+R
greenShift+G
yellowShift+Y
blueShift+B
playShift+P
pauseShift+O
stopShift+S
nextShift+N
prevShift+V
fast_fwdShift+F
rewindShift+W
play_pauseShift+A
infoShift+I

Beyond these keyboard shortcuts, another accessibility feature is that clicking or touching an element sets focus to it and triggers the "enter" key event (i.e. itv-event-enter) on that element.

You may test this for yourself in the following example:

Events - Context

As explained previously, you may associate JavaScript with events are triggered by specific HTML elements. A result of this is that during the execution of the associated Javascript, the value of the this variable references the current HTML element that received the event. To demonstrate this, let's take the following example:

<div id="myButton" itv-event-enter="itv.log(this.id)">

If you trigger the "enter" event on that <div> element, this.id will have the value of "myButton".

On top of that, in certain circumstances, another variable that is added to the context in which the JavaScript is executed. This depends on the event that was triggered. Here is a list of the variables that are added to the context:

EventVariableValueRangeOccurrence
itv-event-numericnumericThe value of the numeric key that was pressed[0..9]Any element that can receive a key event
itv-event-alphaalphaThe value of the alpha key that was pressed[a..z]Any element that can receive a key event
itv-event-indexindexThe value of the index that got selectedpositive integerTemplate - Mosaic elements

To demonstrate this, let's take the following example:

<div id="myButton" itv-event-numeric="itv.log(this.id + ' : ' + numeric)">

If you press a numeric key while focused on this element, the output of the log will be "myButton : X", X being the numeric key you pressed.

You may test this for yourself in the following example:

Events - Propagation

Internally generated events do not bubble up, whereas user generated events do until they are captured.

What does this mean?

Why is it done this way?

This enables you to associate an action to be performed when a key is pressed:

You may test this for yourself in the following example:

Navigation

Navigating a TV interface using a remote control is different to navigating a desktop with a keyboard/mouse or a smartphone/tablet with a touch screen. With a TV interface you usually need to be aware of where you are currently located and move from one focusable item to another. Even though all browsers have a native focus mechanism, the TV framework doesn't use it. The reason for this is that browsers automatically scroll into view a focused element that is outside its parent frame when the parent has the style overflow:hidden. This is problematic when you want to animate focus transitions yourself. So, instead of using the native element.focus(), you have to use the framework built in itv.setFocus(element). Further more, you also need to set itv-focusable=1 to all elements that you wish to be able to focus to. Then, the framework not only changes which element has virtual focus but also updates the visibility of elements if necessary (more on this will be discussed in the Screen functionality). Finally, for a focused element to stand out, all you have to do is set a specific style associated to the CSS class .focused.

Sometimes, it is also useful to provide functionality that isn't linked to a specific element but is available screen wide. For this, you may want to provide visual help to know what these functionalities may be, and which keys they are associated with. This is commonly referred to as a navigational bar.

Navigation - Spatial

Warning: Spatial navigation is not implemented yet.

The simplest way of making elements navigable is to let the framework figure it out depending on the location, size and visibility of every potential focusable element. For this to happen, you need to add the itv-nav="spatial" attribute to the elements for which you want automatic spacial navigation to occur. Don't forget to set the desired style attributes to the .focused class in your CSS also.

Here is an example:

<body itv-event-load="itv.setKeys(0x10);itv.setFocus('button1')">
	<div id="button1" itv-focusable=1 itv-nav="spatial">
		Button 1
	</div>
	<div id="button2" itv-focusable=1 itv-nav="spatial">
		Button 2
	</div>
	<div id="button3" itv-focusable=1 itv-nav="spatial">
		Button 3
	</div>
</body>

After the initial itv.setFocus() is called during the load event triggered on the <body> element, the rest of the navigation is performed without having to specifically declare where to set the focus to on navigational key presses.

You may test this for yourself in the following example:

Navigation - Explicit

Sometimes, you need more control over navigation. This is especially true when you wish to navigate to elements that are not yet visible, since they are located on another Screen. This is done by explicitly defining where the focus goes when you press a key. For this, you need to call itv.setFocus() inside an event handler (typically a navigational key event).

To demonstrate this, we can take the previous example used to demonstrate spatial navigation and add explicit navigational rules as follows:

<body itv-event-load="itv.setKeys(0x10);itv.setFocus('button1')">
	<div id="button1"
		 itv-focusable=1
		 itv-event-down="itv.setFocus('button3')">
		Button 1
	</div>
	<div id="button2"
		 itv-focusable=1
		 itv-event-up="itv.setFocus('button1')"
		 itv-event-down="itv.setFocus('button3')">
		Button 2
	>/div>
	<div id="button3"
		 itv-focusable=1
		 itv-event-up="itv.setFocus('button1')">
		Button 3
	</div>
</body>

You will notice here that pressing the down key when focused on "button1" no longer automatically takes you to "button2" as it did previously but is explicitly set to "button3". Likewise, "button3" takes you to "button1" instead of "button2" when you go up. In this case, you can no longer navigate to "button2" using the navigational keys. That said, if you run this application on a desktop or tablet browser, you can click/touch "button2" in order to bypass these iTV navigational rules.

You may test this for yourself in the following example:

Navigation - Global

Another common use case is to have globally available functionality linked to key events. To perform this functionality, we rely on the bubbling up mechanism of events mentioned earlier (cf. Events - Propagation). In order to inform the user what those functionalities are, you may display a navigational bar, often referred to as a navbar. The framework doesn't impose a specific way of displaying a navbar, it is up to the application developer to create the HTML/CSS for this as best suits him. What the framework does do, is provide the mechanism to handle the functionality of this navbar.

To demonstrate this, we can take the previous example used to demonstrate explicit navigation and add an event handler that captures numerical keys on the top most element, the <body>.

<body itv-event-load="itv.setKeys(0x10+0x100);itv.setFocus('button1')"
	  itv-event-numeric="itv.setFocus('button'+numeric)">
	<div id="button1"
		 itv-focusable=1
		 itv-event-down="itv.setFocus('button3')">
		Button 1
	</div>
	<div id="button2"
		 itv-focusable=1
		 itv-event-up="itv.setFocus('button1')"
		 itv-event-down="itv.setFocus('button3')">
		Button 2
	>/div>
	<div id="button3"
		 itv-focusable=1
		 itv-event-up="itv.setFocus('button1')">
		Button 3
	</div>
</body>

You will notice that the value 0x100 has been added to itv.setKeys() in order to capture numerical keys (cf. Key Masks). This is done in case the application runs on an HbbTV compliant browser. Then, inside the numeric event handler on the <body> element, the value of the numerical key pressed is found in the numeric variable that is usable inside the context of this handler. You are now able to shift focus to "button2" again by pressing the numerical key 2.

You may test this for yourself in the following example:

Screen

In order for a web application to be reactive, a typical practice is to have the different screens of an interface be all part of a single page. This is commonly known as a single-page application. With the iTV.js Framework, it is easy to set up multiple screens that are displayed when needed.

Screen - Standard

To create a screen, all that is needed is to add an itv-screen attribute with no associated value to a container element. What this does is that this screen will be displayed as long as one of the elements it contains is focused. If none of the contained elements are focused, the screen disappears.

Here is an example:

<body itv-event-load="itv.setKeys(0x10);itv.setFocus('button1')" style="visibility:hidden">
	<div itv-screen>
		<h1>Screen 1</h1>
		<div id="button1"
			 itv-focusable=1
			 itv-event-enter="itv.setFocus('button2')">
			Go to Screen 2
		</div>
	</div>
	<div itv-screen>
		<h1>Screen 2</h1>
		<div id="button2"
			 itv-focusable=1
			 itv-event-enter="itv.setFocus('button1')">
			Go to Screen 1
		</div>
	</div>
</body>

In this example, we have 2 screens. Since we set the initial focus to "button1", only the first screen will be displayed. Then, if we press enter to go to screen 2, this first screen disappears and the second screen takes its place.

You may wonder why we have added style="visibility:hidden" to the <body> element? This is done to prevent the flickering that occurs during the lapse of time between when the HTML elements composing the page are ready and displayed and when the framework is up and running. The framework then automatically updates the visibility once an element is focused.

You may test this for yourself in the following example:

Screen - Group

Sometimes, you may want to be able to display a screen without necessarily having the focus set inside it. This typically occurs when you have a focusable element that is visible but outside a group of sub-screens. To do this, all you have to do is to add a label to your group of screens as follows: itv-screen="myGroupLabel". What this does is that all the screens that have the same label form a group of screens. Only one screen of a group is visible at a time. By default, the one that is visible is the first screen of this group. Otherwise it is the last one to have had a focused element inside it.

Here is an example:

<body itv-event-load="itv.setKeys(0x10);itv.setFocus('button1')" style="visibility:hidden">
	<div itv-screen>
		<h1>Screen 1</h1>
		<div id="button1"
			 itv-focusable=1
			 itv-event-enter="itv.setFocus('button1-1')">
			Go to Sub-Screen 1
		</div>
		<div itv-screen="myScreenLabel">
			<h2>Sub-Screen 1</h2>
			<div id="button1-1"
				 itv-focusable=1
				 itv-event-enter="itv.setFocus('button1-2')"
				 itv-event-back="itv.setFocus('button0')">
				Go to Sub-Screen 2
			</div>
		</div>
		<div itv-screen="myScreenLabel">
			<h2>Sub-Screen 2</h2>
			<div id="button1-2"
				 itv-focusable=1
				 itv-event-enter="itv.setFocus('button2')"
				 itv-event-back="itv.setFocus('button0')">
				Go to Screen 2
			</div>
		</div>
	</div>
	<div itv-screen>
		<h1>Screen 2</h1>
		<div id="button2"
			 itv-focusable=1
			 itv-event-enter="itv.setFocus('button1')">
			Go to Screen 1
		</div>
	</div>
</body>

In this example, we have 4 screens: 2 "main" screens and 2 "sub" screens inside the first "main" screen. We can navigate from one screen to the other by pressing enter on the various buttons. We start with the first main screen being visible because the focus is on one of its containing elements. The first sub screen is also visible because it is part of a group, even though no elements inside it are focused. When we move the focus to "button2" on the second main screen, the other main screen and the sub screens inside it disappear.

You may test this for yourself in the following example:

Templates

Now that you have the capacity of handling events and navigating inside screens, the next thing you probably would like to do is manipulate dynamic data and inject it inside widgets. This is where the itv-template attribute comes into play.

Templates - Text

The simplest template available is itv-template="text". Once you have added this attribute to an HTML element, you may use the double curly braces inside this element as place holders for dynamic data as such:

<span id="myTemplateID" itv-template="text">
	Fruits : {{ ['apples', 'peaches', 'oranges'].join(' | ') + ', id : ' + this.id }}
</span>

Inside that element, the text will be rendered as follows : "Fruits : apples | peaches | oranges, id : myTemplateID".

What actually happens under the hood is that the content of that span element is parsed and what is inside the double curly braces is executed as JavaScript. This means that you can put whatever you want inside those braces as long as it evaluates to a String. You will have noticed that the this variable refers to the template element in which this JavaScript was called.

If you wish to update the template because data has changed, you may use itv.update("myTemplateID").

You may test this for yourself in the following example:

Templates - Mosaic

One of the most commonly used data structures that you need to represent on screen is a list. Whether it is a list of days, films, channels, images... you basically need to display items horizontally or vertically and be able to navigate through them and eventually select one. When you come to think of it, a grid or mosaic of items is actually just a list with a 2 dimensional layout. Another way to view this is that a one dimensional list is a flat mosaic. Furthermore, if there are many items, you may want to display them across multiple pages and be able to navigate inside them.

To fulfill all these needs, the framework offers a "mosaic" template. It is invoked by adding the attribute itv-template="mosaic" to an HTML element. What this template does is replicate whatever is inside it by applying certain rules. The number of replications depends on the amount of data you use. Then, you may want to change how many rows or columns this mosaic has, if the mosaic is populated from left to right or from top to bottom (one row or one column being a simple list). In case there are several pages, you may want to specify if the scrolling is done horizontally or vertically along with how the scrolling takes place.

All these features are available by specifying certain attributes to this template. Here is a list of them along with how they modify the template they are applied to:

The values of the attributes itv-data, itv-index, itv-rows and itv-cols are interpreted as JavaScript. This means that the following two examples will give you the same result:

<html>
	<body itv-event-load="itv.setKeys(0x10);itv.setFocus('myMosaic')">
		<div id="myMosaic"
			 itv-focusable=1
			 itv-template="mosaic"
			 itv-data="['A', 'B', 'C', 'D', 'E', 'F']"
			 itv-index="3"
			 itv-rows="4">
			<div>{{this.id + " : " + (i + 1) + "/" + data.length + " : " + data[i]}}</div>
		</div>
	</body>
</html>

Is equivalent to:

<html>
	<head>
		<script>
			var initialIndex = 3,
				rowCount = 4;
			function getData () {
				// This could be data retrieved via an HTTP request.
				return ['A', 'B', 'C', 'D', 'E', 'F'];
			}
		</script>
	</head>
	<body itv-event-load="itv.setKeys(0x10);itv.setFocus('myMosaic')">
		<div id="myMosaic"
			 itv-focusable=1
			 itv-template="mosaic"
			 itv-data="getData()"
			 itv-index="initialIndex"
			 itv-rows="rowCount">
			<div>{{this.id + " : " + (i + 1) + "/" + data.length + " : " + data[i]}}</div>
		</div>
	</body>
</html>

As you can see, the same curly braces described in the text template applies here. You have the same access to the this variable but also have other variables that have been added to the context. These variables are data which refers to the value of itv-data and i which is the Nth iteration of the index that goes from 0 to data.length - 1 during the creation process of the mosaic items.

You may test this for yourself in the following examples:

Video

There are different types of video streams to consider depending on the source. Indeed, you may access a video via multiple protocols such as "http://", "https://", "ftp://", "ftps://", "hls://", "file://", etc. or you may want to display a live satellite, terrestrial or cable feed. Unfortunately, the HbbTV committee didn't go with the now de facto HTML5 <video> element preferring to use a <object type="video/mpeg"></object> element to manipulate file streaming and a <object type="video/broadcast"></object> element to manipulate a live DVB feed.

For the moment, this framework does very little to specifically support video playback. An upcoming releases will introduce an intelligent way of handling the HTML5 <video> element and gracefully fall back to the HbbTV way of handling things if necessary.

In the mean time, you need to implement whatever technique is necessary depending on the target you are aiming at. Thankfully, this isn't too difficult.

Here is an example of how to playback a video using the <video> element:

Here is an example of how to manipulate the live DVB broadcast feed the HbbTV way:

API

The iTV.js framework exposes only one global variable: itv. It is the object through which you can access all functions that are available in this framework. You are free to use any third party JavaScript library/framework such as jQuery, Prototype, Mootools or any other that suits you best. That said, remember that you might not really need one. This is especially true since you probably do not need to support legacy Internet Explorer quirks.

Here is an exhaustive list of what is available in the itv object. It is purposefully short, concentrating on the bare essentials: