Web UI Framework (UIFW): Creating UI Components
This tutorial demonstrates how you can use the Web UI Framework (UIFW), which provides TAU (Tizen Advanced UI Library). TAU is the standard Web UI library for the Tizen platform. It is a collection of UI components that simplify application coding.
Warm-up
Become familiar with the Tizen Web UI Framework API basics by learning about:
-
Creating a Simple Application
Create an application with a header and a footer button.
-
Managing Pages
Use pages to organize your application screens.
-
Managing Page Routing
Change between multiple application pages.
-
Managing UI Components
Use UI components in your application, and modify their behavior and appearance.
-
Creating a Notepad Application
Create an application that allows the user to create and manage notes, and displays the notes on the main page.
Note |
---|
Some of the functionality shown in the use cases may not work properly in a desktop browser. To fully get the TAU experience, use a real Tizen device or the Emulator from the Tizen SDK. |
Creating a Simple Application
To create a simple application in a Web browser:
-
To create a wearable application with a header and a footer button for closing the application, use the following code:
<div class="ui-page ui-page-active"> <div class="ui-header">MyApplication</div> <div class="ui-content">Hello world</div> <div class="ui-footer"> <button id="closeBtn" class="ui-btn">Close</button> </div> <script> var closeBtn = document.getElementById("closeBtn"); closeBtn.addEventListener("click", function () { window.history.back(); }); </script> </div>
-
To create a similar mobile application:
<div data-role="page"> <div data-role="header">MyApplication</div> <div data-role="content">Hello world</div> <div data-role="footer"> <button data-role="button">Close</button> </div> </div>
Note |
---|
In mobile applications, pages are constructed using the data-role attribute, while the wearable applications use the class attribute. In addition, the value of the data-role attribute in mobile applications differs from the class attribute value in the wearable applications. |
For more information on the standalone Web application concept, see Managing Pages.
Managing Pages
The basic building block of an application UI in the TAU library is the Page element, which includes all other elements. The element is optional and extendable, so you can have any element for grouping controls you want.
The page consist of:
- Header area
Shows the user which page is currently open. The header can contain buttons, menus, and toolbars. The header is optional.
- Content area
Contains the main application content. The content area has an optional scroll bar.
- Footer area
Contains a status line or buttons. The footer is optional.
All the page areas are specified by a corresponding class attribute.
Figure: Page content
If there is no Page element in the markup, TAU creates one. For example, if no Page element exists:
<span>I have no page</span>
TAU creates it and moves the content to it:
<div class="ui-page"> Simple page </div>
To create a page on your own, use the class attribute with the ui-page value for wearable applications. TAU uses that information to properly acquire the div element and bind the DOM element to its JavaScript widget implementation.
Note |
---|
In mobile applications, pages are constructed using the data-role attribute, while the wearable applications use the class attribute. In addition, the value of the data-role attribute in mobile applications differs from the class attribute value in the wearable applications. |
To create a page:
-
Create a header area by using the class="ui-header" attribute:
<div class="ui-page"> <div class="ui-header">This is a header</div> </div>
-
Create a footer area by using the class="ui-footer" attribute:
<div class="ui-page"> <div class="ui-footer">This is a footer</div> </div>
-
Create the main content area by using the class="ui-content" attribute:
<div class="ui-page"> <div class="ui-header">MyApplication header</div> <div class="ui-content"> Hello world! </div> <div class="ui-footer">Application status line</div> </div>
-
The previous example shows a full page structure. The header and footer areas can contain multiple UI components, such as buttons or images.
The following example shows a title bar with a More Options button and an icon:
<div class="ui-page"> <div class="ui-header"> <h2 class="ui-title ui-icon" style="background-image: url(image.png);">Title</h2> <button type="button" class="ui-more ui-icon-overflow">More Options</button> </div> <div class="ui-content">MyApplication content</div> </div>
-
You can also create a popup for your page:
<div class="ui-page"> <div class="ui-header">Popup Open Page</div> <div class="ui-content"> <a href="#popup" class="ui-btn" data-rel="popup">Popup Open</a> </div> <div id="popup" class="ui-popup"> <div class="ui-popup-header">Popup Page</div> <div class="ui-popup-content">Popup Content</div> </div> </div>
The popup works because TAU opens (makes visible) the page whose id attribute corresponds to the #hashtag page. This is basic page routing; for more information see Managing Page Routing.
Note Not all profiles contain same UI components, for example, the popup component is only implemented in wearable applications.
Managing Page Routing
TAU is basically a UI framework, but since its purpose is to ease application building, it also provides basic functionality for changing pages in multi-screen applications. The mechanics behind page routing are simple, and works without any additional JavaScript code. If necessary, you can use the API to get more powerful page routing functionalities.
To manage page routing:
- To route without JavaScript:
TAU routing is based on URL hash changes, and it has a built-in mechanism for history tracking. The framework responds to #hashtag changes and tries to display the page that has the id attribute equal to the hashtag value. This approach works for pages defined inside the same HTML document.
TAU uses every <a> element in the page and binds routing methods for them. In addition, all button instances that are based on that tag and have a proper href attribute work with the framework router. The active page has an ui-page-active class assigned. Set that class yourself to be sure the correct page is displayed.
<!--pageOne.html--> <div class="ui-page ui-page-active" id="first"> <div class="ui-content"> <a href="pageTwo.html">Go to page two</a> </div> </div> <!--pageTwo.html--> <div class="ui-page" id="two"> <div class="ui-content"> <a href="pageOne.html">Go to page one</a> </div> </div>
Note In mobile applications, pages are constructed using the data-role attribute, while the wearable applications use the class attribute. In addition, the value of the data-role attribute in mobile applications differs from the class attribute value in the wearable applications. - To route using the API:
You can change pages through the TAU API by using the tau.changePage() method:
<!--pageTwo.html--> <div class="ui-page ui-page-active" id="first"> <div class="ui-content"> You are viewing the first page of the example. <button id="first-button">Click here to change to page two</button> </div> <script> var el1 = document.getElementById("first-button"); el1.addEventListener("click", function () { tau.changePage("pageTwo.html"); }); </script> </div> <!--pageTwo.html--> <div class="ui-page" id="second"> <div class="ui-content"> This is the second page of the example. <button id="second-button">Click here to change to page one</button> </div> <script> var el2 = document.getElementById("second-button"); el2.addEventListener("click", function () { tau.changePage("pageOne.html"); }); </script> </div>
- To load pages from external resources:
When an external page is supplied to the routing engine, TAU fetches that page and appends it to the current document, while changing the base element's href attribute to that page path. This ensures that all other resources, such as CSS, JS, or images, are loaded from the correct path without no real page reloads. Instead, TAU simply switches the current page to the new page.
To load pages from external resources, define the proper local address in the href attribute of the link:
<div class="ui-page"> <div class="ui-content"> <a href="external_text.html">Change to external</a> </div> </div>
To create an external link that is not supposed to be handled by the TAU router, use the rel="external", data-ajax="false", or target="_self" attribute:
<div class="ui-page"> <div class="ui-content"> <a href="external_text.html" target="_self">Change to external</a> </div> </div>
Managing UI Components
A UI component is basically a UI element with specific functionality, such as an input text box, a drop-down menu, or a touch slider. UI components build your application interface, and can be used anywhere in the application. They speed up application development, since much of the work for handling the UI is implemented in them. Some UI components are directly visible, while others are not (for example, the layout UI component).
A "UI component":
- Is a graphical element.
- Displays data and modifies other elements.
- Allows data modification.
- Offers easy development.
The TAU UI components have high performance. The previous web-ui-fw framework, based on jQuery Mobile, was actually an extension. The framework was redefined, conforming to the Tizen platform. The UI components and the look were also redefined. TAU goes a step further still, breaking the dependence on jQuery and jQuery Mobile, while still being compatible with the latter.
The TAU components were rewritten from scratch, with a different architecture in half of them. Simply put, the building phase (which means creating, modifying, and removing elements and properties), which ensures the "look" of the UI component and its structure, and the control logic were separated. This allows pre-building the markup for faster application runtime and startup.
The key features of the TAU components are:
- Performance
- Pre-building
- Easy to use API
- Compatibility with jQuery Mobile
- Look and feel
A basic UI component implements 5 protected methods:
-
build is responsible for the UI component creation.
Note The build method is not executed every time the UI component is created, and it does not run when the markup is already built.
- configure is expected to configure all the options for the UI component.
- init handles the initialization, like searching for UI component sub-elements.
- bindEvents handles all event binding (from user interaction).
- destroy removes all listeners, and cleans up after the UI component.
The UI component is registered in the core engine by the tau.engine.defineWidget method, with its name, selector, and public methods list for jQuery Mobile compatibility (as needed).
A given document element can have multiple UI components created from it, which really means that one element is 2 or more UI components at the same time. This behavior prevents much of the code duplication and can be used to create UI components which are complementary, such as input with a drop-down list.
To create UI components:
- Create a basic UI component.
A UI component can be created through multiple ways, the first and recommended one is to create a specific markup which conforms to the UI component selector. For example, to create a Button UI component:
<button type="myButton" class="ui-btn">This is a button</button>
The above code causes TAU to create a Button, because the ui-btn class matches the UI component's selector. Some UI components have multiple selectors:
><a href="#hashtag" class="ui-btn">Button</a>
The above code also creates a button, since the ui-btn class is matches the Button UI component selector.
UI components can also be created on ambiguous elements, that do not match specific selectors, using JavaScript code:
<div class="ui-page"> <div id="IndexScrollbar"></div> <script> var element = document.getElementById("IndexScrollbar"); tau.widget.IndexScrollbar(element); </script> </div>
Note Creating UI components dynamically from JavaScript code is not recommended as this prevents pre-building the markup.
- Customize the UI components.
Almost all UI components support options which change their look and behavior. The options can be changed either on UI component creation or sometimes at runtime. To specify the options, you can use 2 methods:
-
Use the data-\* attributes, where \* stands for the option name.
<a href="popup.html" data-rel="popup" data-transition="slideup">I'll slide up</a>
-
When your UI component is created dynamically, pass the options to the tau.widget UI component method:
<div class="ui-page"> <div id="IndexScrollbar"></div> <script> var element = document.getElementById("IndexScrollbar"); tau.widget.IndexScrollbar(element, { index: "A,B,C,D" }); </script> </div>
-
- Fetch data and modify behavior.
You want to be able to fetch and store information in a UI component, not just modify its look and feel. For this purpose, all UI components expose their API, with only one rule: protected methods (marked with "_" underscore) must not be run directly.
Some methods are getters and setters, and some modify the UI component behavior. For example, the value method is a setter method:
<input type="checkbox" checked /> <script> document.addEventListener("pageshow", function () { var inputElement = document.querySelector("input"), input = tau.engine.instanceWidget(inputElement, "Checkboxradio"); window.setTimeout(function () { input.value(false); /* Toggle checkbox */ }, 2500); }); </script>
Creating a Notepad Application
The notepad application shows all the notes in the main page, and allows the user to add new notes, edit existing notes, and delete notes by swiping them. The notes on the main page can be scrolled and edited, and a button is provided for adding a new note. After you click a note, it is displayed in the edit page for editing.
To create a simple notepad application using the TAU library:
- Generate an application from the Tizen SDK.
Create a simple basic application that can be used for further development:
- In the IDE menu, go to File > New > Tizen Web Project > WEARABLE-2.3 > Wearable UI > Basic Application.
- Enter the application name as Notes and click Finish.
The IDE creates the application with a default file structure.
- Edit the section header for the index.html file.
Because the application runs on mobile or wearable devices, make sure that you have the correct tau.css styles for the corresponding profile:
- Mobile:
<link rel="stylesheet" type="text/css" href="lib/tau/mobile/theme/default/tau.min.css"/>
- Wearable:
<link rel="stylesheet" type="text/css" href="lib/tau/wearable/theme/default/tau.min.css"/>
Add also your own styles for the application:
<link rel="stylesheet" type="text/css" href="css/style.css"/>
The following example shows how the section header looks after editing:
<head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0"> <meta name="description" content="Tizen basic template generated by Tizen Web IDE"/> <title>Notepad</title> <!--Use 'mobile' or 'wearable' to choose the device TAU profile--> <link rel="stylesheet" type="text/css" href="lib/tau/mobile/theme/default/tau.css"/> <link rel="stylesheet" type="text/css" href="css/style.css"/> </head>
- Mobile:
- Create the pages: the main page for displaying the notes and the editing page for adding and editing notes.
- The main page is the first page, defined with the div block with the ui-page class and main id.
- Add the title header (Notes) for the page:
<div id="main" class="ui-page"> <header class="ui-header"> <h1>Notes</h1> </header> </div>
- Add content for the main page by adding a div element with
the _ui-content class. Add to this a ul element, which creates the list of notes.
Set the data-scroll="y" and data-handler="true" attributes.
The item in the list is represented as a li element. When a note on the main page is clicked, the application triggers the changepage event to the editor page and shows the item.
<div class="ui-content" data-scroll="y" data-handler="true"> <ul class="ui-listview" id="notesList"></ul> </div>
- Add a navigation button to the application to change to the editor page. The button is placed in the footer, and it is created from an a element,
which has the id="newBtn" attribute.
<div class="ui-footer"> <a href="javascript:void()" id="newBtn">New note</a> </div>
The above examples apply to a wearable application. The following example shows the full code for the main page in a mobile application:
<div class="ui-page" id="main"> <div class"ui-header" data-position="fixed"> <h1>Notes</h1> </div> <div class="ui-content" data-scroll="y" data-handler="true"> <ul class="ui-listview" id="notesList"></ul> </div> <div class="ui-footer"> <a href="javascript:void()" id="newBtn">New note</a> </div> </div>
Note In mobile applications, pages are constructed using the data-role attribute, while the wearable applications use the class attribute. In addition, the value of the data-role attribute in mobile applications differs from the class attribute value in the wearable applications. - Add the title header (Notes) for the page:
- On the editing page, the header and footer are similar to main page. The only difference is that the
action triggered after pressing the button adds an item to the items array and adds the item to the top of the visible list. The editing page is defined with a div block with
the id="editor" and class="ui-page" attributes.
The editing page is needed for adding or editing a selected note. It has a textarea element to allow the user to edit the selected note.
<!--This code applies to wearable applications--> <div class="ui-page" id="editor"> <div class="ui-header"> <h1>Editor</h1> </div> <div class="ui-content"> <textarea id="editorField" placeholder="enter note"></textarea> </div> <div class="ui-footer"> <a href="javascript:void()" id="saveBtn">Save</a> </div> </div>
- The main page is the first page, defined with the div block with the ui-page class and main id.
- Link to the TAU library sources and add the script to the application:
<script src="js/jquery.js"></script> <script type="text/javascript" src="js/lib/tau/mobile/js/tau.js" data-build-remove="false"></script> <script src="js/main.js"></script>
The index.html file is now ready.
- Add styles for the content:
a { color: #FFF; } #notesList.ui-listview { width: 100%; } #notesList.ui-listview li { margin: 0; white-space: nowrap; } #notesList.ui-listview li .ui-inline { position: absolute; right: 5px; top: 5px; } #notesList.ui-listview li .ui-swipe-item-cover-inner { text-overflow: ellipsis; overflow: hidden; } #editor .ui-scrollview-view { height: 100%; } #editor textarea { height: 95%; width: 100%; }
- Create the main.js file and create a function to close the application:
<script> (function () { 'use strict'; var newBtn = document.getElementById('newBtn'), saveBtn = document.getElementById('saveBtn'), editorField = document.getElementById('editorField'), notesList = document.getElementById('notesList'), editorPage = document.getElementById('editor'), mainPageId = '#main', editorPageId = '#editor', currentIndex = null, EMPTY_CONTENT = '(empty)', STORAGE_KEY = 'notepad'; /** * Get data from local storage * @return {Array} */ function getStorage(key) { return JSON.parse(window.localStorage.getItem(key)) || false; } /** * Add data to local storage * @param {Array} data */ function addStorage(data) { window.localStorage.setItem(STORAGE_KEY, JSON.stringify(data)); } /** * Return current page ID * @returns */ function getCurrentPageId() { return $('[data-role="page"]:visible')[0].id; } /* Refresh current page */ function refreshCurrentPage() { $('#' + getCurrentPageId()).trigger('create'); } /** * Get notes from storage * @return {Array} */ function getNotes() { return getStorage(STORAGE_KEY) || []; } /* Clear list with notes */ function clearNotesList() { notesList.innerHTML = ''; } /* Delete note from storage */ function deleteNote(index) { var notes = getNotes(); if (notes[index] !== undefined) { notes.splice(index, 1); addStorage(notes); } else { console.error('deleteNote: note not found'); } showNotes(); refreshCurrentPage(); event.stopPropagation(); } /** * Edit note using array index * @param index */ function editNote(index) { var notes = getNotes(); if (notes[index] !== undefined) { currentIndex = index; editorField.value = getNotes()[index]; tau.changePage(editorPageId); } else { console.error('editNote: note not found'); showNotes(); refreshCurrentPage(); } } /* Show all notes extracted from local storage */ function showNotes() { var notes = getNotes(), notesLen = notes.length, li = {}, swipeCover = {}, swipeItem = {}, deleteBtn = {}, i = 0, notesListInst; clearNotesList(); for (i; i < notesLen; i += 1) { li = document.createElement('li'); li.addEventListener('click', editNote.bind(this, i), false); deleteBtn = document.createElement('div'); deleteBtn.setAttribute('data-role', 'button'); deleteBtn.setAttribute('data-inline', 'true'); deleteBtn.innerText = 'Delete'; deleteBtn.addEventListener('click', deleteNote.bind(this, i), false); li.innerText = notes[i].replace(/\n/g, ' ') || EMPTY_CONTENT; li.appendChild(deleteBtn); notesList.appendChild(li); notesListInst = tau.widget.getInstance(notesList); tau.widget.Button(deleteBtn); notesListInst.refresh(); } } /* Clear editor textarea */ function clearEditor() { editorField.value = ''; } /* Save note to storage */ function saveNote() { var notes = getNotes(); if (currentIndex !== null) { notes[currentIndex] = editorField.value; } else { notes.push(editorField.value); } addStorage(notes); clearEditor(); showNotes(); tau.changePage(mainPageId); } /* New note button handler */ function newNote() { currentIndex = null; clearEditor(); tau.changePage(editorPageId); } /* On editor page show handler */ function onEditorPageShow() { editorField.focus(); } /* Attach events */ function events() { newBtn.addEventListener('click', newNote); saveBtn.addEventListener('click', saveNote); editorPage.addEventListener('pageshow', onEditorPageShow); $(window).on('tizenhwkey', function (e) { if (e.originalEvent.keyName === "back" && window.tizen && window.tizen.application) { switch (getCurrentPageId()) { case 'main': window.tizen.application.getCurrentApplication().exit(); break; default: window.history.back(); break; } return false; } }); } /* Initialize */ function init() { showNotes(); events(); } init(); }()); </script>
Now the application is ready and you can deploy it to a device or Emulator.