View on GitHub

TAU

TAU (Tizen Advanced UI) project for supporting web app development based on web-based ui widget components library

How to write apps using declarative widgets

TAU widgets are, at the ground level, normal HTML markup elements that are enchanced with JavaScriot logic. The problem with normal basic HTML markup is that it does not exactly help to access the logic, so a global variable/namespace has to be used to get the JS logic for a specific widget ex. window.tau object. TAU supports CustomElements API to allow easy access to JavaScript widget code and to simplify widget markup.

An example can be shown of two ways we can create a widget and access the JS representation of that element.

<div data-role="page" id="myPage">hello world!</div>
<script>
	document.addEventListener("pageshow", function (e) {
		var pageElement = document.getElementById("myPage"),
			pageWidget = tau.engine.instanceWidget(pageElement, "page");
	}, false);
</script>

As we can see the markup is a little bloated and the JS code is not optimal. When CustomElements are used we can write as in example:

<tau-page id="myPage">hello world!</tau-page>
<script>
	document.addEventListener("pageshow", function () {
		var pageWidget = document.getElementById("myPage")._tauWidget;
	}, false);
</script>

The code is simple and straightforward.

Element properties

As seen in the example in the previous chapter, class and/or data-role attributes are not used to create widgets. Each widget has its own tag, like in the mentioned example, the Page widget is creating by using <tau-page> tag.

<tau-page>my page content <tau-button>my button</tau-button></tau-page>

When using TAU with its declarative markup API, almost all properties stay the same with one difference. The data- prefix is not needed anymore, we can lose it in most widgets. For example, when we want to disable the overlay layer for a popup:

<tau-popup overlay="false">
	Popup
</tau-popup>

Control elements

The only difference that is visible is when using control elements like input, select etc. They are written as before but we add the is attribute, which tells the browser what widget the element represents.

<input is="tau-textinput">

This is still CustomElements specification and is implement this way to properly handle extending of native browser elements

Simple notes application

So, having the basics covered, we can write a simple Notes application to demonstrate the usage of the declarative API. First we need 2 pages, first of the note list and second for edit/add form

<tau-page id="main">
	<header>Notes</header>
	<tau-scrollview class="ui-content">
		<tau-listview id="list" class="ui-listview">
			<li class="ui-li-static">Example note (click to edit)</li>
		</tau-listview>
	</tau-scrollview>
	<footer><button id="add">Add</button></footer>
</tau-page>
<tau-page id="form">
	<header>Notes</header>
	<tau-scrollview class="ui-content">
		<textarea is="tau-textarea" id="data" rows="10"></textarea>
	</tau-scrollview>
	<footer>
		<button id="cancel">Cancel</button>
		<button id="save">Save</button>
	</footer>
</tau-page>

We also need some JS logic to handle managing of note data. As show in the example by using the simplified API that is bound to the element itself we can ease the process of interacting with TAU widgets.

<tau-page id="main">
	<header>Notes</header>
	<tau-scrollview class="ui-content">
		<tau-listview id="list" class="ui-listview">
			<li class="ui-li-static">Example note (click to edit)</li>
		</tau-listview>
	</tau-scrollview>
	<footer><button id="add">Add</button></footer>
</tau-page>
<tau-page id="form">
	<header>Notes</header>
	<tau-scrollview class="ui-content">
		<textarea is="tau-textarea" id="data" rows="10"></textarea>
	</tau-scrollview>
	<footer>
		<button id="cancel">Cancel</button>
		<button id="save">Save</button>
	</footer>
</tau-page>
<script>
	// initialize the code on first pageshow call
	tau.event.one(document, "pageshow", function () {
		var list = document.getElementById("list"),
			listPage = document.getElementById("main"),
			addPage = document.getElementById("form"),
			addButton = document.getElementById("add"),
			cancelButton = document.getElementById("cancel"),
			saveButton = document.getElementById("save"),
			inputData = document.getElementById("data")._tauWidget,
			currentNoteIndex = -1,
			notes = [];

		list._tauWidget.refresh();

		// load existing data
		[].slice.call(list.children).forEach(function (note) {
			notes.push(note.textContent);
		});

		function addNoteElement(data) {
			var listElement = document.createElement("li");
			listElement.textContent = data;
			listElement.className = "ui-li-static";
			list.appendChild(listElement);
		}

		function updateNoteElement(index, data) {
			if (index > -1) {
				list.children[index].textContent = data;
			}
		}

		function removeNoteElement(index) {
			if (index > -1) {
				list.removeChild(list.children[index]);
			}
		}

		tau.event.on(addButton, "click", function () {
			tau.changePage(addPage);
		});

		tau.event.on(cancelButton, "click", function () {
			currentNode = -1;
			tau.history.back();
		});

		// handle adding of new, editing and deletion
		tau.event.on(saveButton, "click", function () {
			var value = inputData.value().trim();
			if (currentNoteIndex === -1 && value.length > 0) {
				addNoteElement(value);
				notes.push(value);
			} else {
				if (value.length > 0) {
					notes[currentNoteIndex] = value
					updateNoteElement(currentNoteIndex, value);
				} else {
					notes.splice(currentNoteIndex, 1);
					removeNoteElement(currentNoteIndex);
				}
				currentNoteIndex = -1;
			}
			tau.changePage(listPage);
		});

		tau.event.on(addPage, "pagebeforeshow", function () {
			if (currentNoteIndex > -1) {
				inputData.value(notes[currentNoteIndex]);
			} else {
				inputData.value("");
			}
			inputData.refresh();
			addPage._tauWidget.refresh();
		});

		tau.event.on(listPage, "pagebeforeshow", function (event) {
			event.target._tauWidget.refresh();
		});

		tau.event.on(list, "click", function (event) {
			var target = event.target;
			if (target.parentNode === list && target.tagName.toLowerCase() === "li") {
				currentNoteIndex = [].slice.call(list.children).indexOf(target);
				tau.changePage(addPage);
			}
		});
	});
</script>